diff --git a/app/Domains/Badges/UseCases/GetBadges.php b/app/Domains/Badges/UseCases/GetBadges.php index 10e0577d5..14e45237b 100644 --- a/app/Domains/Badges/UseCases/GetBadges.php +++ b/app/Domains/Badges/UseCases/GetBadges.php @@ -2,22 +2,17 @@ namespace App\Domains\Badges\UseCases; -use App\Core\Domains\MinecraftUUID\Data\MinecraftUUID; use App\Models\Badge; use App\Models\MinecraftPlayer; +use Illuminate\Support\Collection; final class GetBadges { - public function execute(MinecraftUUID $uuid): array + public function execute(MinecraftPlayer $player): Collection { - $player = MinecraftPlayer::whereUuid($uuid)->first(); - if ($player === null) { - return []; - } - $account = $player->account; if ($account === null) { - return []; + return collect(); } $badges = $account->badges; @@ -29,6 +24,6 @@ public function execute(MinecraftUUID $uuid): array $badge->unicode_icon = '⌚'; $badges->add($badge); - return $badges->toArray(); + return $badges; } } diff --git a/app/Domains/Bans/UseCases/GetActivePlayerBan.php b/app/Domains/Bans/UseCases/GetActivePlayerBan.php deleted file mode 100644 index 6d467d0bf..000000000 --- a/app/Domains/Bans/UseCases/GetActivePlayerBan.php +++ /dev/null @@ -1,22 +0,0 @@ -first(); - if ($player === null) { - return null; - } - - return GamePlayerBan::where('banned_player_id', $player->getKey()) - ->active() - ->first(); - } -} diff --git a/app/Domains/Donations/UseCases/DeactivateExpiredDonorPerks.php b/app/Domains/Donations/UseCases/DeactivateExpiredDonorPerks.php index 13782bd3e..fc949f6f0 100644 --- a/app/Domains/Donations/UseCases/DeactivateExpiredDonorPerks.php +++ b/app/Domains/Donations/UseCases/DeactivateExpiredDonorPerks.php @@ -20,7 +20,7 @@ public function execute(): void return; } - $donorGroup = Group::where('name', Group::DONOR_GROUP_NAME)->first(); + $donorGroup = Group::whereDonor()->first(); if ($donorGroup === null) { throw new \Exception('Could not find donor group'); } diff --git a/app/Domains/Donations/UseCases/GetDonationTiers.php b/app/Domains/Donations/UseCases/GetDonationTiers.php deleted file mode 100644 index cf761b902..000000000 --- a/app/Domains/Donations/UseCases/GetDonationTiers.php +++ /dev/null @@ -1,41 +0,0 @@ -with('account.donationPerks.donationTier') - ->first(); - - if ($existingPlayer === null) { - throw new NotFoundException('player_not_found', 'Minecraft player not found for given UUID'); - } - - $account = $existingPlayer->account; - if ($account === null) { - throw new NotFoundException('player_not_linked', 'Minecraft player not linked to an account'); - } - - $perks = $account->donationPerks - ->where('is_active', true) - ->where('expires_at', '>', now()) - ->unique('donation_tier_id'); - - if ($perks === null || count($perks) === 0) { - return []; // No donation perks for this account - } - - return $perks->values()->toArray(); - } -} diff --git a/app/Domains/Donations/UseCases/ProcessPayment.php b/app/Domains/Donations/UseCases/ProcessPayment.php index 64e86de50..a0e93f093 100644 --- a/app/Domains/Donations/UseCases/ProcessPayment.php +++ b/app/Domains/Donations/UseCases/ProcessPayment.php @@ -38,7 +38,7 @@ public function execute( throw new BadRequestException(id: 'invalid_quantity', message: 'Quantity purchased was zero'); } - $donorGroup = Group::where('name', Group::DONOR_GROUP_NAME)->first(); + $donorGroup = Group::whereDonor()->first(); if ($donorGroup === null) { throw new \Exception('Could not find donor group'); } diff --git a/app/Http/Controllers/Api/v2/Minecraft/MinecraftPlayerController.php b/app/Http/Controllers/Api/v2/Minecraft/MinecraftPlayerController.php index 0b4118b31..182dcfb29 100644 --- a/app/Http/Controllers/Api/v2/Minecraft/MinecraftPlayerController.php +++ b/app/Http/Controllers/Api/v2/Minecraft/MinecraftPlayerController.php @@ -5,9 +5,9 @@ use App\Core\Domains\MinecraftUUID\Data\MinecraftUUID; use App\Domains\Badges\UseCases\GetBadges; use App\Domains\Bans\UseCases\GetActiveIPBan; -use App\Domains\Bans\UseCases\GetActivePlayerBan; use App\Domains\Donations\UseCases\GetDonationTiers; use App\Http\Controllers\ApiController; +use App\Models\GamePlayerBan; use App\Models\Group; use App\Models\MinecraftPlayer; use Illuminate\Http\JsonResponse; @@ -18,45 +18,50 @@ final class MinecraftPlayerController extends ApiController public function __invoke( Request $request, MinecraftUUID $uuid, - GetActivePlayerBan $getBan, GetBadges $getBadges, - GetDonationTiers $getDonationTier, GetActiveIPBan $getActiveIPBan, ): JsonResponse { $request->validate([ 'ip' => 'ip', ]); - $ban = $getBan->execute(uuid: $uuid); - $badges = $getBadges->execute(uuid: $uuid); + $player = MinecraftPlayer::whereUuid($uuid) + ->with(['account.groups', 'account.donationPerks.donationTier.group']) + ->first(); - $donationTiers = rescue( - callback: fn () => $getDonationTier->execute(uuid: $uuid), - rescue: [], - report: false, - ); - - $ipBan = null; - if ($request->has('ip')) { - $ipBan = $getActiveIPBan->execute(ip: $request->get('ip')); - } - - $player = MinecraftPlayer::whereUuid($uuid)->first(); $player?->touchLastSyncedAt(); - $account = $player?->account; + + $donationTiers = optional($account, function ($account) { + return $account->donationPerks + ->where('is_active', true) + ->where('expires_at', '>', now()) + ->map(fn ($it) => $it->donationTier); + }) ?: collect(); + + $groups = $account?->groups ?: collect(); if ($account !== null && $account->groups->isEmpty()) { - // TODO: change this to model attribute - $account->groups->push(Group::whereDefault()->first()); + $groups->add(Group::whereDefault()->first()); + } + + $donorGroups = $donationTiers->map(fn ($tier) => $tier->group); + if (!$donorGroups->isEmpty()) { + $groups = $groups->merge($donorGroups); } return response()->json([ - 'account' => $account, + 'account' => $account?->withoutRelations(), 'player' => $player?->withoutRelations(), - 'ban' => $ban, - 'badges' => $badges, - 'donation_tiers' => $donationTiers, - 'ip_ban' => $ipBan, + 'groups' => $groups, + 'ban' => optional($player, function ($player) { + return GamePlayerBan::where('banned_player_id', $player->getKey()) + ->active() + ->first(); + }), + 'badges' => optional($player, fn ($player) => $getBadges->execute($player)), + 'ip_ban' => $request->has('ip') + ? $getActiveIPBan->execute(ip: $request->get('ip')) + : null, ]); } } diff --git a/app/Models/DonationPerk.php b/app/Models/DonationPerk.php index cf3df78d3..954c78b91 100644 --- a/app/Models/DonationPerk.php +++ b/app/Models/DonationPerk.php @@ -29,7 +29,6 @@ final class DonationPerk extends Model implements LinkableAuditModel 'expires_at', 'created_at', 'updated_at', - 'last_currency_reward_at', ]; protected $casts = [ diff --git a/app/Models/DonationTier.php b/app/Models/DonationTier.php index f3c12040e..1f90ad650 100644 --- a/app/Models/DonationTier.php +++ b/app/Models/DonationTier.php @@ -8,6 +8,7 @@ use App\Core\Utilities\Traits\HasStaticTable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\BelongsTo; final class DonationTier extends Model implements LinkableAuditModel { @@ -26,6 +27,15 @@ final class DonationTier extends Model implements LinkableAuditModel public $timestamps = false; + public function group(): BelongsTo + { + return $this->belongsTo( + related: Group::class, + foreignKey: 'group_id', + ownerKey: 'group_id', + ); + } + public function getActivitySubjectLink(): ?string { return null; diff --git a/app/Models/Group.php b/app/Models/Group.php index e49acc9bd..a7153f1b6 100644 --- a/app/Models/Group.php +++ b/app/Models/Group.php @@ -14,8 +14,6 @@ final class Group extends Model implements LinkableAuditModel use HasFactory; use HasStaticTable; - public const DONOR_GROUP_NAME = 'donator'; - protected $table = 'groups'; protected $primaryKey = 'group_id'; @@ -27,7 +25,6 @@ final class Group extends Model implements LinkableAuditModel 'is_default', 'is_staff', 'is_admin', - 'discourse_name', 'minecraft_name', 'minecraft_display_name', 'minecraft_hover_text', @@ -71,6 +68,11 @@ public function scopeWhereDefault(Builder $query) $query->where('is_default', true); } + public function scopeWhereDonor(Builder $query) + { + $query->where('name', 'donator'); + } + public function getActivitySubjectLink(): ?string { return route('front.panel.groups.index').'#group-'.$this->getKey(); diff --git a/database/factories/GroupFactory.php b/database/factories/GroupFactory.php index 54c5b5e59..7aef47fb1 100644 --- a/database/factories/GroupFactory.php +++ b/database/factories/GroupFactory.php @@ -24,7 +24,9 @@ public function definition(): array 'is_default' => false, 'is_staff' => false, 'is_admin' => false, - 'discourse_name' => $this->faker->randomLetter(), + 'discord_name' => $this->faker->name(), + 'minecraft_display_name' => $this->faker->name(), + 'minecraft_hover_text' => $this->faker->name(), ]; } @@ -36,7 +38,7 @@ public function member(): Factory return $this->state(function (array $attributes) { return [ 'name' => 'member', - 'discourse_name' => 'member', + 'discord_name' => 'member', 'is_default' => true, ]; }); @@ -50,7 +52,7 @@ public function donor(): Factory return $this->state(function (array $attributes) { return [ 'name' => 'donator', - 'discourse_name' => 'donator', + 'discord_name' => 'donator', ]; }); } @@ -63,7 +65,7 @@ public function administrator(): Factory return $this->state(function (array $attributes) { return [ 'name' => 'Administrator', - 'discourse_name' => 'administrator', + 'discord_name' => 'administrator', 'is_staff' => true, 'is_admin' => true, 'can_access_panel' => true, diff --git a/database/factories/MinecraftConfigFactory.php b/database/factories/MinecraftConfigFactory.php index 0192ea704..69bdc768d 100644 --- a/database/factories/MinecraftConfigFactory.php +++ b/database/factories/MinecraftConfigFactory.php @@ -20,13 +20,14 @@ public function definition(): array { return [ 'version' => 1, - 'config' => json_encode([ + 'config' => [ 'localization' => [ 'time_zone' => 'UTC', 'locale' => 'en-us', ], 'chat' => [ - 'badge_icon' => '★', + 'badge_icon' => '', + 'staff_channel' => '(Staff) : ', ], 'warps' => [ 'items_per_page' => 15, @@ -50,7 +51,7 @@ public function definition(): array 'first_time_join' => '✦ Welcome to the server!', 'welcome' => 'Welcome to PROJECT CITY BUILD| | Type /menu to access most server features, including rank| applications, warps, player reporting, and other information.| Hold down the TAB key to see who else is online.| Ask our staff if you have any questions.', ], - ]), + ], ]; } } diff --git a/database/factories/WarpFactory.php b/database/factories/MinecraftWarpFactory.php similarity index 94% rename from database/factories/WarpFactory.php rename to database/factories/MinecraftWarpFactory.php index d9078e987..4cb12ba4a 100644 --- a/database/factories/WarpFactory.php +++ b/database/factories/MinecraftWarpFactory.php @@ -4,7 +4,7 @@ use App\Models\MinecraftWarp; -class WarpFactory extends Factory +class MinecraftWarpFactory extends Factory { protected $model = MinecraftWarp::class; diff --git a/database/migrations/2024_10_30_110257_add_minecraft_group_cols.php b/database/migrations/2024_10_30_110257_add_minecraft_group_cols.php new file mode 100644 index 000000000..f17db2fd9 --- /dev/null +++ b/database/migrations/2024_10_30_110257_add_minecraft_group_cols.php @@ -0,0 +1,56 @@ +dropColumn('discourse_name'); + $table->integer('display_priority')->nullable()->after('minecraft_name'); + $table->string('minecraft_hover_text')->after('minecraft_name'); + $table->string('minecraft_display_name')->after('minecraft_name'); + $table->string('group_type')->nullable(); + }); + + Schema::table('donation_perks', function (Blueprint $table) { + $table->dropColumn('last_currency_reward_at'); + }); + + Schema::table('donation_tiers', function (Blueprint $table) { + $table->dropColumn('currency_reward'); + $table->unsignedInteger('group_id')->nullable(); + + $table->foreign('group_id')->references('group_id')->on('groups'); + }); + + $group = Group::first(); + if ($group === null) { + $group = Group::factory()->create(); + } + DonationTier::get()->each(function ($tier) use($group) { + $tier->group_id = $group->getKey(); + $tier->save(); + }); + + Schema::table('donation_tiers', function (Blueprint $table) { + $table->unsignedInteger('group_id')->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 2ba21d4fb..fb5cbe983 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -4,6 +4,8 @@ use App\Models\MinecraftConfig; use App\Models\MinecraftWarp; +use App\Models\Server; +use App\Models\ServerToken; use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder @@ -18,9 +20,14 @@ public function run() $this->call(PlayerWarningSeeder::class); $this->call(DonationSeeder::class); $this->call(BadgeSeeder::class); - $this->call(ServerTokenSeeder::class); $this->call(ShowcaseWarpSeeder::class); + ServerToken::create([ + 'token' => 'pcbridge_local', + 'server_id' => Server::first()->getKey(), + 'description' => 'For test use', + ]); + MinecraftConfig::factory() ->create(); diff --git a/database/seeders/DonationSeeder.php b/database/seeders/DonationSeeder.php index 36080b572..45a489430 100644 --- a/database/seeders/DonationSeeder.php +++ b/database/seeders/DonationSeeder.php @@ -6,6 +6,7 @@ use App\Models\Donation; use App\Models\DonationPerk; use App\Models\DonationTier; +use App\Models\Group; use App\Models\StripeProduct; use Illuminate\Database\Seeder; @@ -13,17 +14,31 @@ class DonationSeeder extends Seeder { public function run() { + $copperGroup = Group::factory()->create([ + 'name' => 'copper tier', + 'minecraft_name' => 'copper_tier', + ]); $copperTier = DonationTier::create([ 'name' => 'copper', - 'currency_reward' => 10, + 'group_id' => $copperGroup->getKey(), + ]); + + $ironGroup = Group::factory()->create([ + 'name' => 'iron tier', + 'minecraft_name' => 'iron_tier', ]); $ironTier = DonationTier::create([ 'name' => 'iron', - 'currency_reward' => 25, + 'group_id' => $ironGroup->getKey(), + ]); + + $diamondGroup = Group::factory()->create([ + 'name' => 'diamond tier', + 'minecraft_name' => 'diamond_tier', ]); $diamondTier = DonationTier::create([ 'name' => 'diamond', - 'currency_reward' => 50, + 'group_id' => $diamondGroup->getKey(), ]); // Copper subscription diff --git a/database/seeders/GroupSeeder.php b/database/seeders/GroupSeeder.php index 6cb4e776f..829bcfb03 100644 --- a/database/seeders/GroupSeeder.php +++ b/database/seeders/GroupSeeder.php @@ -20,65 +20,115 @@ public function run() $scopes->put(key: $scope->value, value: $model->getKey()); }); - Group::create([ - 'name' => 'retired', - ]); - - Group::create([ + Group::factory()->create([ 'name' => 'member', + 'minecraft_name' => 'default', + 'minecraft_display_name' => '[M]', + 'minecraft_hover_text' => 'Member', 'is_default' => true, + 'group_type' => 'trust', + 'display_priority' => 1, ]); - Group::create([ + Group::factory()->create([ 'name' => 'trusted', + 'minecraft_name' => 'trusted', + 'minecraft_display_name' => '[T]', + 'minecraft_hover_text' => 'Trusted', + 'group_type' => 'trust', + 'display_priority' => 2, ]); - Group::create([ + Group::factory()->create([ 'name' => 'trusted+', + 'minecraft_name' => 'trusted_plus', + 'minecraft_display_name' => '[T+]', + 'minecraft_hover_text' => 'Trusted+', + 'group_type' => 'trust', + 'display_priority' => 3, ]); - Group::create([ + Group::factory()->create([ 'name' => 'intern', + 'minecraft_name' => 'intern', + 'minecraft_display_name' => '[I]', + 'minecraft_hover_text' => 'Intern', 'is_build' => true, + 'group_type' => 'build', + 'display_priority' => 1, ]); - Group::create([ + Group::factory()->create([ 'name' => 'builder', + 'minecraft_name' => 'builder', + 'minecraft_display_name' => '[B]', + 'minecraft_hover_text' => 'Builder', 'is_build' => true, + 'group_type' => 'build', + 'display_priority' => 2, ]); - Group::create([ + Group::factory()->create([ 'name' => 'planner', + 'minecraft_name' => 'planner', + 'minecraft_display_name' => '[P]', + 'minecraft_hover_text' => 'Planner', 'is_build' => true, + 'group_type' => 'build', + 'display_priority' => 3, ]); - Group::create([ + Group::factory()->create([ 'name' => 'engineer', + 'minecraft_name' => 'engineer', + 'minecraft_display_name' => '[E]', + 'minecraft_hover_text' => 'Engineer', 'is_build' => true, + 'group_type' => 'build', + 'display_priority' => 4, ]); - $architect = Group::create([ + $architect = Group::factory()->create([ 'name' => 'architect', + 'minecraft_name' => 'architect', + 'minecraft_display_name' => '[A]', + 'minecraft_hover_text' => 'Architect', 'is_build' => true, + 'group_type' => 'build', + 'display_priority' => 5, ]); $architect->groupScopes()->attach([ $scopes[PanelGroupScope::ACCESS_PANEL->value], $scopes[PanelGroupScope::REVIEW_BUILD_RANK_APPS->value], ]); - Group::create([ + Group::factory()->create([ 'name' => 'donator', + 'minecraft_name' => 'donator', + 'minecraft_display_name' => '[$]', + 'minecraft_hover_text' => 'Donator', + 'group_type' => 'donor', + 'display_priority' => 1, ]); - Group::create([ + Group::factory()->create([ 'name' => 'legacy donor', 'minecraft_name' => 'legacy-donor', + 'minecraft_display_name' => '[$]', + 'minecraft_hover_text' => 'Donator (Legacy)', + 'group_type' => 'donor', + 'display_priority' => 2, ]); - $mod = Group::create([ + $mod = Group::factory()->create([ 'name' => 'moderator', + 'minecraft_name' => 'moderator', + 'minecraft_display_name' => '[Staff]', + 'minecraft_hover_text' => 'Moderator', 'alias' => 'Mod', 'is_staff' => true, + 'group_type' => 'staff', + 'display_priority' => 1, ]); $mod->groupScopes()->attach([ $scopes[PanelGroupScope::ACCESS_PANEL->value], @@ -86,12 +136,17 @@ public function run() $scopes[PanelGroupScope::REVIEW_BUILD_RANK_APPS->value], ]); - $dev = Group::create([ + $dev = Group::factory()->create([ 'name' => 'developer', + 'minecraft_name' => 'develop', + 'minecraft_display_name' => '[Staff]', + 'minecraft_hover_text' => 'Developer', 'alias' => 'Dev', 'is_staff' => true, 'is_admin' => true, 'can_access_panel' => true, + 'group_type' => 'staff', + 'display_priority' => 2, ]); $dev->groupScopes()->attach( collect($scopes)->values()->toArray(), diff --git a/database/seeders/ServerSeeder.php b/database/seeders/ServerSeeder.php index 326239916..36385a9ef 100644 --- a/database/seeders/ServerSeeder.php +++ b/database/seeders/ServerSeeder.php @@ -11,7 +11,7 @@ public function run() { Server::factory()->create([ 'name' => 'Minecraft (Java)', - 'ip' => '158.69.120.168', + 'ip' => 'host.docker.internal', 'ip_alias' => 'pcbmc.co', 'port' => '25565', 'web_port' => '8080', diff --git a/database/seeders/ServerTokenSeeder.php b/database/seeders/ServerTokenSeeder.php deleted file mode 100644 index 87d2539b2..000000000 --- a/database/seeders/ServerTokenSeeder.php +++ /dev/null @@ -1,20 +0,0 @@ - (new SecureTokenGenerator())->make(), - 'server_id' => Server::first()->getKey(), - 'description' => 'For test use', - ]); - } -}