HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/be.naniguide.com/app/Http/Controllers/Refactor/Ads/AdPlatformController.php
<?php

namespace App\Http\Controllers\Refactor\Ads;

use App\Http\Controllers\Controller;
use App\Model\AdPlatform;
use App\Services\Ads\AdPlatformManager;
use App\Services\Ads\AdActivityLogger;
use App\Services\Ads\AdPlatformException;
use App\Services\Ads\AdCredentialResolver;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

class AdPlatformController extends Controller
{
    protected AdPlatformManager $manager;

    public function __construct(AdPlatformManager $manager)
    {
        $this->manager = $manager;
    }

    /**
     * Platform connections index page.
     */
    public function index(Request $request)
    {
        $customer = $request->user()->customer;

        $provisioningStatus = [];
        foreach (AdPlatform::PLATFORMS as $platform) {
            $provisioningStatus[$platform] = AdCredentialResolver::isConfigured($platform);
        }

        return view('refactor.pages.ads.platforms.index', [
            'platforms' => $customer->local()->adPlatforms()->active()->get(),
            'availablePlatforms' => AdPlatform::PLATFORMS,
            'platformLabels' => AdPlatform::PLATFORM_LABELS,
            'provisioningStatus' => $provisioningStatus,
        ]);
    }

    /**
     * AJAX listing partial.
     */
    public function listing(Request $request)
    {
        $customer = $request->user()->customer;
        $platforms = $customer->local()->adPlatforms()
            ->search($request->keyword)
            ->orderBy('created_at', 'desc')
            ->get();

        return view('refactor.pages.ads.platforms._list', [
            'platforms' => $platforms,
        ]);
    }

    /**
     * Initiate OAuth connection flow.
     */
    public function connect(Request $request, string $platform)
    {
        if (!in_array($platform, AdPlatform::PLATFORMS)) {
            return redirect()->route('refactor.ads.platforms.index')
                ->with('error', trans('refactor/ads_platforms.invalid_platform'));
        }

        // Phase N — fail-fast if admin hasn't configured this platform yet.
        // Return friendly empty state instead of letting an empty client_id hit OAuth URL.
        if (!app(\App\Services\Ads\AdPlatformManager::class)->isMockMode() && !AdCredentialResolver::isConfigured($platform)) {
            return redirect()->route('refactor.ads.platforms.index')
                ->with('error', trans('refactor/ads_platforms.not_configured', [
                    'platform' => AdPlatform::PLATFORM_LABELS[$platform],
                ]));
        }

        // Plan quota gate — canAccept() encapsulates the 4-state limit semantic.
        $customer = $request->user()->customer;
        $quotas   = app(\App\Services\Plans\Quotas\QuotasService::class);
        $qKey     = \App\Services\Plans\Quotas\QuotaKey::MAX_ADS_PLATFORMS;

        if (! $quotas->canAccept($customer, $qKey, 1)) {
            // Distinguish "not on plan" (no row) from "cap reached".
            $errKey = $quotas->limit($customer, $qKey) === false
                ? 'refactor/ads_platforms.not_on_plan'
                : 'refactor/ads_platforms.quota_exceeded';
            return redirect()->route('refactor.ads.platforms.index')
                ->with('error', trans($errKey));
        }

        // Generate CSRF state parameter
        $state = Str::random(40);
        session(['ads_oauth_state' => $state, 'ads_oauth_platform' => $platform]);

        $redirectUri = route('refactor.ads.platforms.callback', ['platform' => $platform]);
        $adapter = $this->manager->adapter($platform);
        // Phase N — adapter is single source of truth for default scopes
        $scopes = $adapter->getDefaultScopes();

        $authUrl = $adapter->getAuthUrl($redirectUri, $scopes, $state);

        return redirect($authUrl);
    }

    /**
     * OAuth callback handler.
     */
    public function callback(Request $request, string $platform)
    {
        // Verify CSRF state
        $expectedState = session('ads_oauth_state');
        $receivedState = $request->input('state');

        if (!$expectedState || $expectedState !== $receivedState) {
            return redirect()->route('refactor.ads.platforms.index')
                ->with('error', trans('refactor/ads_platforms.oauth_state_mismatch'));
        }

        session()->forget(['ads_oauth_state', 'ads_oauth_platform']);

        if ($request->has('error')) {
            return redirect()->route('refactor.ads.platforms.index')
                ->with('error', trans('refactor/ads_platforms.oauth_denied', ['message' => $request->input('error_description', $request->input('error'))]));
        }

        $code = $request->input('code') ?? $request->input('auth_code');
        if (!$code) {
            return redirect()->route('refactor.ads.platforms.index')
                ->with('error', trans('refactor/ads_platforms.oauth_no_code'));
        }

        try {
            $redirectUri = route('refactor.ads.platforms.callback', ['platform' => $platform]);
            $adapter = $this->manager->adapter($platform);
            $tokenResult = $adapter->handleCallback($code, $redirectUri);

            $customer = $request->user()->customer;
            $adPlatform = $this->manager->connect($customer->local(), $platform, $tokenResult);

            return redirect()->route('refactor.ads.platforms.index')
                ->with('success', trans('refactor/ads_platforms.connected', ['platform' => $adPlatform->platform_label]));
        } catch (AdPlatformException $e) {
            AdActivityLogger::log(
                entity: new AdPlatform(['customer_id' => $request->user()->customer->id, 'id' => 0]),
                action: 'platform.connect_failed',
                status: 'error',
                title: AdPlatform::PLATFORM_LABELS[$platform] . ' connection failed',
                errorCode: $e->getPlatformCode(),
                errorMessage: $e->getMessage(),
                resolutionHint: $e->getResolutionHint(),
                platform: $platform,
            );

            return redirect()->route('refactor.ads.platforms.index')
                ->with('error', $e->getMessage());
        }
    }

    /**
     * Disconnect a platform.
     */
    public function disconnect(Request $request, string $uid)
    {
        $customer = $request->user()->customer;
        $platform = $customer->local()->adPlatforms()->where('uid', $uid)->firstOrFail();

        $this->manager->disconnect($platform);

        return response()->json([
            'status' => 'success',
            'message' => trans('refactor/ads_platforms.disconnected', ['platform' => $platform->platform_label]),
        ]);
    }

    /**
     * Run health check on a platform.
     */
    public function healthCheck(Request $request, string $uid)
    {
        $customer = $request->user()->customer;
        $platform = $customer->local()->adPlatforms()->where('uid', $uid)->firstOrFail();

        $result = $this->manager->runHealthCheck($platform);

        return response()->json([
            'status' => $result->status,
            'message' => $result->message,
            'health_status' => $platform->fresh()->health_status,
        ]);
    }

    /**
     * Refresh platform token manually.
     */
    public function refresh(Request $request, string $uid)
    {
        $customer = $request->user()->customer;
        $platform = $customer->local()->adPlatforms()->where('uid', $uid)->firstOrFail();

        $this->manager->refreshIfExpired($platform);

        return response()->json([
            'status' => 'success',
            'message' => trans('refactor/ads_platforms.token_refreshed'),
        ]);
    }

    /**
     * Get ad accounts for a platform.
     */
    public function accounts(Request $request, string $uid)
    {
        $customer = $request->user()->customer;
        $platform = $customer->local()->adPlatforms()->where('uid', $uid)->firstOrFail();

        return response()->json([
            'accounts' => $platform->accounts()->get()->map(function ($account) {
                return [
                    'uid' => $account->uid,
                    'name' => $account->name,
                    'currency' => $account->currency,
                    'is_default' => $account->is_default,
                ];
            })->values(),
        ]);
    }

    /**
     * Set default ad account for a platform.
     */
    public function setDefaultAccount(Request $request, string $uid)
    {
        $customer = $request->user()->customer;
        $platform = $customer->local()->adPlatforms()->where('uid', $uid)->firstOrFail();

        $accountUid = $request->input('account_uid');
        $account = $platform->accounts()->where('uid', $accountUid)->firstOrFail();

        // Clear existing default
        $platform->accounts()->update(['is_default' => false]);
        $account->update(['is_default' => true]);

        return response()->json([
            'status' => 'success',
            'message' => trans('refactor/ads_platforms.default_account_set', ['name' => $account->name]),
        ]);
    }

}