Skip to content

Commit 0feb69b

Browse files
committed
Merge branch 'main' into plugins-docs
2 parents c4573ea + 4fd8e40 commit 0feb69b

File tree

98 files changed

+9130
-77
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+9130
-77
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Models\User;
6+
use App\Support\DiscordApi;
7+
use Illuminate\Console\Command;
8+
9+
class RemoveExpiredDiscordRoles extends Command
10+
{
11+
protected $signature = 'discord:remove-expired-roles';
12+
13+
protected $description = 'Remove Discord Max role for users whose Max licenses have expired';
14+
15+
public function handle(): int
16+
{
17+
$discord = DiscordApi::make();
18+
$removed = 0;
19+
20+
$users = User::query()
21+
->whereNotNull('discord_role_granted_at')
22+
->whereNotNull('discord_id')
23+
->get();
24+
25+
foreach ($users as $user) {
26+
if (! $user->hasMaxAccess()) {
27+
$success = $discord->removeMaxRole($user->discord_id);
28+
29+
if ($success) {
30+
$user->update([
31+
'discord_role_granted_at' => null,
32+
]);
33+
34+
$this->info("Removed Discord role for user: {$user->email} ({$user->discord_username})");
35+
$removed++;
36+
} else {
37+
$this->error("Failed to remove Discord role for user: {$user->email} ({$user->discord_username})");
38+
}
39+
}
40+
}
41+
42+
$this->info("Total users with Discord role removed: {$removed}");
43+
44+
return Command::SUCCESS;
45+
}
46+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Models\User;
6+
use App\Support\GitHubOAuth;
7+
use Illuminate\Console\Command;
8+
9+
class RemoveExpiredGitHubAccess extends Command
10+
{
11+
protected $signature = 'github:remove-expired-access';
12+
13+
protected $description = 'Remove GitHub repository access for users whose Max licenses have expired';
14+
15+
public function handle(): int
16+
{
17+
$github = GitHubOAuth::make();
18+
$removed = 0;
19+
20+
// Find users with GitHub access granted
21+
$users = User::query()
22+
->whereNotNull('mobile_repo_access_granted_at')
23+
->whereNotNull('github_username')
24+
->get();
25+
26+
foreach ($users as $user) {
27+
// Check if user still has Max access (direct or sub-license)
28+
if (! $user->hasMaxAccess()) {
29+
// Remove from repository
30+
$success = $github->removeFromMobileRepo($user->github_username);
31+
32+
if ($success) {
33+
// Clear the access timestamp
34+
$user->update([
35+
'mobile_repo_access_granted_at' => null,
36+
]);
37+
38+
$this->info("Removed access for user: {$user->email} (@{$user->github_username})");
39+
$removed++;
40+
} else {
41+
$this->error("Failed to remove access for user: {$user->email} (@{$user->github_username})");
42+
}
43+
}
44+
}
45+
46+
$this->info("Total users with access removed: {$removed}");
47+
48+
return Command::SUCCESS;
49+
}
50+
}

app/Console/Kernel.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ protected function schedule(Schedule $schedule): void
1717
->dailyAt('09:00')
1818
->onOneServer()
1919
->runInBackground();
20+
21+
// Remove GitHub access for users with expired Max licenses
22+
$schedule->command('github:remove-expired-access')
23+
->dailyAt('10:00')
24+
->onOneServer()
25+
->runInBackground();
26+
27+
// Remove Discord Max role for users with expired Max licenses
28+
$schedule->command('discord:remove-expired-roles')
29+
->dailyAt('10:30')
30+
->onOneServer()
31+
->runInBackground();
2032
}
2133

2234
/**

app/Enums/LicenseSource.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ enum LicenseSource: string
77
case Stripe = 'stripe';
88
case Bifrost = 'bifrost';
99
case Manual = 'manual';
10+
case OpenCollective = 'opencollective';
1011
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
namespace App\Filament\Resources;
4+
5+
use App\Filament\Resources\LeadResource\Pages;
6+
use App\Models\Lead;
7+
use Filament\Infolists;
8+
use Filament\Infolists\Infolist;
9+
use Filament\Resources\Resource;
10+
use Filament\Tables;
11+
use Filament\Tables\Table;
12+
13+
class LeadResource extends Resource
14+
{
15+
protected static ?string $model = Lead::class;
16+
17+
protected static ?string $navigationIcon = 'heroicon-o-banknotes';
18+
19+
protected static ?string $navigationLabel = 'Leads';
20+
21+
protected static ?string $pluralModelLabel = 'Leads';
22+
23+
public static function canCreate(): bool
24+
{
25+
return false;
26+
}
27+
28+
public static function infolist(Infolist $infolist): Infolist
29+
{
30+
return $infolist
31+
->schema([
32+
Infolists\Components\Section::make('Contact Information')
33+
->schema([
34+
Infolists\Components\TextEntry::make('name')
35+
->label('Name'),
36+
Infolists\Components\TextEntry::make('email')
37+
->label('Email')
38+
->copyable(),
39+
Infolists\Components\TextEntry::make('company')
40+
->label('Company'),
41+
])
42+
->columns(3),
43+
44+
Infolists\Components\Section::make('Project Details')
45+
->schema([
46+
Infolists\Components\TextEntry::make('budget_label')
47+
->label('Budget'),
48+
Infolists\Components\TextEntry::make('description')
49+
->label('App Description')
50+
->columnSpanFull(),
51+
]),
52+
53+
Infolists\Components\Section::make('Metadata')
54+
->schema([
55+
Infolists\Components\TextEntry::make('ip_address')
56+
->label('IP Address'),
57+
Infolists\Components\TextEntry::make('created_at')
58+
->label('Submitted')
59+
->dateTime(),
60+
])
61+
->columns(2)
62+
->collapsed(),
63+
]);
64+
}
65+
66+
public static function table(Table $table): Table
67+
{
68+
return $table
69+
->columns([
70+
Tables\Columns\TextColumn::make('name')
71+
->searchable()
72+
->sortable(),
73+
74+
Tables\Columns\TextColumn::make('email')
75+
->searchable()
76+
->sortable(),
77+
78+
Tables\Columns\TextColumn::make('company')
79+
->searchable()
80+
->sortable(),
81+
82+
Tables\Columns\TextColumn::make('budget_label')
83+
->label('Budget')
84+
->sortable(query: function ($query, string $direction) {
85+
return $query->orderBy('budget', $direction);
86+
}),
87+
88+
Tables\Columns\TextColumn::make('created_at')
89+
->label('Submitted')
90+
->dateTime()
91+
->sortable(),
92+
])
93+
->filters([
94+
Tables\Filters\SelectFilter::make('budget')
95+
->options(Lead::BUDGETS),
96+
])
97+
->actions([
98+
Tables\Actions\ViewAction::make(),
99+
])
100+
->bulkActions([
101+
Tables\Actions\BulkActionGroup::make([
102+
Tables\Actions\DeleteBulkAction::make(),
103+
]),
104+
])
105+
->defaultSort('created_at', 'desc');
106+
}
107+
108+
public static function getRelations(): array
109+
{
110+
return [
111+
//
112+
];
113+
}
114+
115+
public static function getPages(): array
116+
{
117+
return [
118+
'index' => Pages\ListLeads::route('/'),
119+
'view' => Pages\ViewLead::route('/{record}'),
120+
];
121+
}
122+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace App\Filament\Resources\LeadResource\Pages;
4+
5+
use App\Filament\Resources\LeadResource;
6+
use Filament\Actions;
7+
use Filament\Resources\Pages\ListRecords;
8+
9+
class ListLeads extends ListRecords
10+
{
11+
protected static string $resource = LeadResource::class;
12+
13+
protected function getHeaderActions(): array
14+
{
15+
return [
16+
Actions\CreateAction::make(),
17+
];
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace App\Filament\Resources\LeadResource\Pages;
4+
5+
use App\Filament\Resources\LeadResource;
6+
use Filament\Actions;
7+
use Filament\Resources\Pages\ViewRecord;
8+
9+
class ViewLead extends ViewRecord
10+
{
11+
protected static string $resource = LeadResource::class;
12+
13+
protected function getHeaderActions(): array
14+
{
15+
return [
16+
Actions\EditAction::make(),
17+
];
18+
}
19+
}

0 commit comments

Comments
 (0)