trypost/app/Http/Middleware/App/HandleInertiaRequests.php
Paulo Castellano 2e9e0f716b feat: capture signup UTMs/IP and add GitHub OAuth login
Persists marketing attribution and registration metadata for new users
across the three signup paths (email, Google, GitHub):

- 5 utm_* columns + registration_ip on the users table
- PreservesUtmParameters trait stores incoming utm_* query params on
  the register/redirect GET, retrieves them on the POST/callback —
  surviving the OAuth round-trip via session
- request()->ip() captured at the controller layer

Adds GitHub as a second OAuth provider:

- GitHubController mirroring the Google one (now renamed from
  SocialLoginController for symmetry)
- Settings → Authentication can connect/disconnect GitHub like Google
- Single SocialLogin.vue component replaces the per-provider buttons
  on Login/Register, rendering each enabled provider plus a single
  "or continue with" divider

UserFactory gains defaults for the new nullable columns so model
strict-mode access in tests doesn't trip.
2026-05-04 18:42:25 -03:00

66 lines
2.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Middleware\App;
use App\Http\Resources\App\HandleInertiaRequests\AuthUserResource;
use App\Http\Resources\App\HandleInertiaRequests\AuthWorkspaceResource;
use App\Models\Account;
use App\Models\Plan;
use Illuminate\Http\Request;
use Inertia\Middleware;
class HandleInertiaRequests extends Middleware
{
protected $rootView = 'app';
public function version(Request $request): ?string
{
return parent::version($request);
}
/**
* @return array<string, mixed>
*/
public function share(Request $request): array
{
$user = $request->user();
$currentWorkspace = $user?->currentWorkspace?->load('media');
$account = $user?->account;
$isSelfHosted = (bool) config('trypost.self_hosted');
return [
...parent::share($request),
'name' => config('app.name'),
'auth' => [
'user' => $user ? AuthUserResource::make($user) : null,
'currentWorkspace' => $currentWorkspace ? AuthWorkspaceResource::make($currentWorkspace, $user) : null,
'workspaces' => $user
? $user->workspaces()->with('media')->get()->map(fn ($ws) => AuthWorkspaceResource::summary($ws))
: [],
'plan' => $account?->plan,
'hasActiveSubscription' => $account ? $account->hasActiveSubscription() : false,
'currentPriceId' => $account?->subscription(Account::SUBSCRIPTION_NAME)?->stripe_price,
],
'usage' => $account && ! $isSelfHosted ? $account->usage() : null,
'features' => $account && ! $isSelfHosted ? $account->featureLimits() : null,
'plans' => $isSelfHosted ? [] : Plan::active()->orderBy('sort')->get(),
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
'flash' => $request->session()->get('flash', []),
'applicationUrl' => config('app.url'),
'env' => config('app.env'),
'locale' => app()->getLocale(),
'languages' => collect(config('languages.available'))->map(fn ($name, $code) => [
'code' => $code,
'name' => $name,
])->values()->all(),
'aiEnabled' => ! empty(config('services.gemini.api_key')) || ! empty(config('services.openai.api_key')),
'selfHosted' => $isSelfHosted,
'googleAuthEnabled' => config('trypost.google_auth_enabled'),
'githubAuthEnabled' => config('trypost.github_auth_enabled'),
'trialDays' => config('cashier.trial_days'),
];
}
}