Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/Console/Commands/RemoveExpiredDiscordRoles.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class RemoveExpiredDiscordRoles extends Command
{
protected $signature = 'discord:remove-expired-roles';

protected $description = 'Remove Discord Max role for users whose Max licenses have expired';
protected $description = 'Remove Discord Ultra role for users whose Max licenses or Ultra subscriptions have ended';

public function handle(): int
{
Expand All @@ -23,8 +23,8 @@ public function handle(): int
->get();

foreach ($users as $user) {
if (! $user->hasMaxAccess()) {
$success = $discord->removeMaxRole($user->discord_id);
if (! $user->hasMaxAccess() && ! $user->hasUltraAccess()) {
$success = $discord->removeUltraRole($user->discord_id);

if ($success) {
$user->update([
Expand Down
8 changes: 4 additions & 4 deletions app/Http/Controllers/DiscordIntegrationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ public function handleCallback(): RedirectResponse

$rolesAssigned = [];

if ($user->hasMaxAccess()) {
if ($discord->assignMaxRole($discordUser['id'])) {
if ($user->hasMaxAccess() || $user->hasUltraAccess()) {
if ($discord->assignUltraRole($discordUser['id'])) {
$user->update(['discord_role_granted_at' => now()]);
$rolesAssigned[] = 'Max';
$rolesAssigned[] = 'Ultra';
}
}

Expand Down Expand Up @@ -117,7 +117,7 @@ public function disconnect(): RedirectResponse
$discord = DiscordApi::make();

if ($user->discord_role_granted_at) {
$discord->removeMaxRole($user->discord_id);
$discord->removeUltraRole($user->discord_id);
}

if ($user->discord_early_adopter_role_granted_at) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class AssignDiscordMaxRoleJob implements ShouldQueue
class AssignDiscordUltraRoleJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

Expand All @@ -31,8 +31,8 @@ public function handle(): void
return;
}

if (! $this->user->hasMaxAccess()) {
Log::info('Skipping Discord role assignment - user has no Max access', [
if (! $this->user->hasMaxAccess() && ! $this->user->hasUltraAccess()) {
Log::info('Skipping Discord role assignment - user has no Max or Ultra access', [
'user_id' => $this->user->id,
]);

Expand All @@ -50,17 +50,17 @@ public function handle(): void
return;
}

$success = $discord->assignMaxRole($this->user->discord_id);
$success = $discord->assignUltraRole($this->user->discord_id);

if ($success) {
$this->user->update(['discord_role_granted_at' => now()]);

Log::info('Discord Max role assigned successfully', [
Log::info('Discord Ultra role assigned successfully', [
'user_id' => $this->user->id,
'discord_id' => $this->user->discord_id,
]);
} else {
Log::error('Failed to assign Discord Max role', [
Log::error('Failed to assign Discord Ultra role', [
'user_id' => $this->user->id,
'discord_id' => $this->user->discord_id,
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class RemoveDiscordMaxRoleJob implements ShouldQueue
class RemoveDiscordUltraRoleJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

Expand All @@ -33,17 +33,17 @@ public function handle(): void

$discord = DiscordApi::make();

$success = $discord->removeMaxRole($this->user->discord_id);
$success = $discord->removeUltraRole($this->user->discord_id);

if ($success) {
$this->user->update(['discord_role_granted_at' => null]);

Log::info('Discord Max role removed successfully', [
Log::info('Discord Ultra role removed successfully', [
'user_id' => $this->user->id,
'discord_id' => $this->user->discord_id,
]);
} else {
Log::warning('Failed to remove Discord Max role (user may not have role)', [
Log::warning('Failed to remove Discord Ultra role (user may not have role)', [
'user_id' => $this->user->id,
'discord_id' => $this->user->discord_id,
]);
Expand Down
6 changes: 3 additions & 3 deletions app/Jobs/RevokeMaxAccessJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,17 @@ private function revokeDiscordRole(User $user): void
}

$discord = DiscordApi::make();
$success = $discord->removeMaxRole($user->discord_id);
$success = $discord->removeUltraRole($user->discord_id);

if ($success) {
$user->update(['discord_role_granted_at' => null]);

Log::info('Discord Max role revoked for user', [
Log::info('Discord Ultra role revoked for user', [
'user_id' => $user->id,
'discord_id' => $user->discord_id,
]);
} else {
Log::warning('Failed to revoke Discord Max role for user', [
Log::warning('Failed to revoke Discord Ultra role for user', [
'user_id' => $user->id,
'discord_id' => $user->discord_id,
]);
Expand Down
12 changes: 6 additions & 6 deletions app/Listeners/StripeWebhookReceivedListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use App\Jobs\CreateUserFromStripeCustomer;
use App\Jobs\HandleInvoicePaidJob;
use App\Jobs\RemoveDiscordMaxRoleJob;
use App\Jobs\RemoveDiscordUltraRoleJob;
use App\Jobs\RevokeTeamUserAccessJob;
use App\Jobs\SuspendTeamJob;
use App\Jobs\UnsuspendTeamJob;
Expand Down Expand Up @@ -75,7 +75,7 @@ private function handleSubscriptionDeleted(WebhookReceived $event): void
return;
}

$this->removeDiscordRoleIfNoMaxLicense($user);
$this->removeDiscordRoleIfNoAccess($user);

dispatch(new SuspendTeamJob($user->id));
dispatch(new RevokeTeamUserAccessJob($user->id));
Expand All @@ -101,7 +101,7 @@ private function handleSubscriptionUpdated(WebhookReceived $event): void
}

if (in_array($status, ['canceled', 'unpaid', 'past_due', 'incomplete_expired'])) {
$this->removeDiscordRoleIfNoMaxLicense($user);
$this->removeDiscordRoleIfNoAccess($user);
dispatch(new SuspendTeamJob($user->id));
dispatch(new RevokeTeamUserAccessJob($user->id));
}
Expand All @@ -112,16 +112,16 @@ private function handleSubscriptionUpdated(WebhookReceived $event): void
}
}

private function removeDiscordRoleIfNoMaxLicense(User $user): void
private function removeDiscordRoleIfNoAccess(User $user): void
{
if (! $user->discord_id) {
return;
}

if ($user->hasMaxAccess()) {
if ($user->hasMaxAccess() || $user->hasUltraAccess()) {
return;
}

dispatch(new RemoveDiscordMaxRoleJob($user));
dispatch(new RemoveDiscordUltraRoleJob($user));
}
}
22 changes: 11 additions & 11 deletions app/Livewire/DiscordAccessBanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class DiscordAccessBanner extends Component
{
public bool $inline = false;

public bool $hasMaxRole = false;
public bool $hasUltraRole = false;

public bool $hasEarlyAdopterRole = false;

Expand All @@ -27,7 +27,7 @@ public function checkRoleStatus(): void
$user = auth()->user();

if (! $user || ! $user->discord_id) {
$this->hasMaxRole = false;
$this->hasUltraRole = false;
$this->hasEarlyAdopterRole = false;
$this->isGuildMember = false;

Expand All @@ -41,16 +41,16 @@ public function checkRoleStatus(): void

return [
'isGuildMember' => $discord->isGuildMember($user->discord_id),
'hasMaxRole' => $discord->hasMaxRole($user->discord_id),
'hasUltraRole' => $discord->hasUltraRole($user->discord_id),
'hasEarlyAdopterRole' => $discord->hasEarlyAdopterRole($user->discord_id),
];
});

$this->isGuildMember = $status['isGuildMember'];
$this->hasMaxRole = $status['hasMaxRole'];
$this->hasUltraRole = $status['hasUltraRole'];
$this->hasEarlyAdopterRole = $status['hasEarlyAdopterRole'];

if ($this->hasMaxRole && ! $user->discord_role_granted_at) {
if ($this->hasUltraRole && ! $user->discord_role_granted_at) {
$user->update(['discord_role_granted_at' => now()]);
}

Expand All @@ -70,7 +70,7 @@ public function refreshStatus(): void
$this->checkRoleStatus();
}

public function requestMaxRole(): void
public function requestUltraRole(): void
{
$user = auth()->user();

Expand All @@ -80,8 +80,8 @@ public function requestMaxRole(): void
return;
}

if (! $user->hasMaxAccess()) {
session()->flash('error', 'You need an active Max license to receive the Max role.');
if (! $user->hasMaxAccess() && ! $user->hasUltraAccess()) {
session()->flash('error', 'You need an active Max license or Ultra subscription to receive the Ultra role.');

return;
}
Expand All @@ -94,15 +94,15 @@ public function requestMaxRole(): void
return;
}

$success = $discord->assignMaxRole($user->discord_id);
$success = $discord->assignUltraRole($user->discord_id);

if ($success) {
$user->update(['discord_role_granted_at' => now()]);
Cache::forget("discord_role_status_{$user->id}");
$this->checkRoleStatus();
session()->flash('success', 'Max role assigned successfully!');
session()->flash('success', 'Ultra role assigned successfully!');
} else {
session()->flash('error', 'Failed to assign Max role. Please try again later.');
session()->flash('error', 'Failed to assign Ultra role. Please try again later.');
}
}

Expand Down
16 changes: 8 additions & 8 deletions app/Support/DiscordApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class DiscordApi
public function __construct(
private ?string $botToken,
private ?string $guildId,
private ?string $maxRoleId,
private ?string $ultraRoleId,
private ?string $earlyAdopterRoleId
) {}

Expand All @@ -21,7 +21,7 @@ public static function make(): static
return new static(
config('services.discord.bot_token', ''),
config('services.discord.guild_id', ''),
config('services.discord.max_role_id', ''),
config('services.discord.ultra_role_id', ''),
config('services.discord.early_adopter_role_id', '')
);
}
Expand Down Expand Up @@ -71,19 +71,19 @@ public function isGuildMember(string $discordUserId): bool
return true;
}

public function assignMaxRole(string $discordUserId): bool
public function assignUltraRole(string $discordUserId): bool
{
return $this->assignRole($discordUserId, $this->maxRoleId, 'Max');
return $this->assignRole($discordUserId, $this->ultraRoleId, 'Ultra');
}

public function removeMaxRole(string $discordUserId): bool
public function removeUltraRole(string $discordUserId): bool
{
return $this->removeRole($discordUserId, $this->maxRoleId, 'Max');
return $this->removeRole($discordUserId, $this->ultraRoleId, 'Ultra');
}

public function hasMaxRole(string $discordUserId): bool
public function hasUltraRole(string $discordUserId): bool
{
return $this->hasRole($discordUserId, $this->maxRoleId);
return $this->hasRole($discordUserId, $this->ultraRoleId);
}

public function assignEarlyAdopterRole(string $discordUserId): bool
Expand Down
2 changes: 1 addition & 1 deletion config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
'redirect' => env('APP_URL').'/auth/discord/callback',
'bot_token' => env('DISCORD_BOT_TOKEN'),
'guild_id' => env('DISCORD_GUILD_ID'),
'max_role_id' => env('DISCORD_MAX_ROLE_ID'),
'ultra_role_id' => env('DISCORD_ULTRA_ROLE_ID'),
'early_adopter_role_id' => env('DISCORD_EARLY_ADOPTER_ROLE_ID'),
],

Expand Down
4 changes: 2 additions & 2 deletions resources/views/livewire/customer/integrations.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<div class="mt-4 prose dark:prose-invert prose-sm max-w-none">
<ul class="list-disc list-inside space-y-2">
<li><strong>GitHub:</strong> Max license holders can access the private <code>nativephp/mobile</code> repository. Plugin Dev Kit license holders and Ultra subscribers can access <code>nativephp/claude-code</code>.</li>
<li><strong>Discord:</strong> Max license holders receive a special "Max" role in the NativePHP Discord server. Early Access Program customers receive the "Early Adopter" role.</li>
<li><strong>Discord:</strong> Max license holders and Ultra subscribers receive a special "Ultra" role in the NativePHP Discord server. Early Access Program customers receive the "Early Adopter" role.</li>
</ul>
<p class="mt-4">
Need help? Join our <a href="https://discord.gg/nativephp" target="_blank" class="text-blue-600 hover:underline dark:text-blue-400">Discord community</a>.
Expand All @@ -47,7 +47,7 @@
<livewire:git-hub-access-banner :inline="true" />
@endif

@if(auth()->user()->isEapCustomer())
@if(auth()->user()->hasMaxAccess() || auth()->user()->hasUltraAccess() || auth()->user()->isEapCustomer())
<livewire:discord-access-banner :inline="true" />
@endif
</div>
Expand Down
18 changes: 9 additions & 9 deletions resources/views/livewire/discord-access-banner.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
</p>
@else
<div class="mt-1 flex flex-wrap gap-1">
@if($hasMaxRole)
@if($hasUltraRole)
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
Max Role Active
Ultra Role Active
</span>
@elseif(auth()->user()->hasMaxAccess())
@elseif(auth()->user()->hasMaxAccess() || auth()->user()->hasUltraAccess())
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200">
Max Eligible
Ultra Eligible
</span>
@endif

Expand Down Expand Up @@ -62,10 +62,10 @@
<span wire:loading wire:target="refreshStatus">Checking...</span>
</button>
@else
@if(!$hasMaxRole && auth()->user()->hasMaxAccess())
<button wire:click="requestMaxRole" type="button" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<span wire:loading.remove wire:target="requestMaxRole">Request Max Role</span>
<span wire:loading wire:target="requestMaxRole">Requesting...</span>
@if(!$hasUltraRole && (auth()->user()->hasMaxAccess() || auth()->user()->hasUltraAccess()))
<button wire:click="requestUltraRole" type="button" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<span wire:loading.remove wire:target="requestUltraRole">Request Ultra Role</span>
<span wire:loading wire:target="requestUltraRole">Requesting...</span>
</button>
@endif
@if(!$hasEarlyAdopterRole && auth()->user()->isEapCustomer())
Expand All @@ -74,7 +74,7 @@
<span wire:loading wire:target="requestEarlyAdopterRole">Requesting...</span>
</button>
@endif
@if(($hasMaxRole || !auth()->user()->hasMaxAccess()) && ($hasEarlyAdopterRole || !auth()->user()->isEapCustomer()))
@if(($hasUltraRole || !(auth()->user()->hasMaxAccess() || auth()->user()->hasUltraAccess())) && ($hasEarlyAdopterRole || !auth()->user()->isEapCustomer()))
<a href="https://discord.gg/nativephp" target="_blank" rel="noopener noreferrer" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Open Discord
</a>
Expand Down
2 changes: 1 addition & 1 deletion tests/Feature/DiscordIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protected function setUp(): void
'services.discord.client_secret' => 'test-client-secret',
'services.discord.bot_token' => 'test-bot-token',
'services.discord.guild_id' => 'test-guild-id',
'services.discord.max_role_id' => 'max-role-id',
'services.discord.ultra_role_id' => 'ultra-role-id',
'services.discord.early_adopter_role_id' => 'early-adopter-role-id',
]);
}
Expand Down
Loading
Loading