user()->role === 'admin', 403); $connection = EtsyConnection::first(); $receipts = []; $listings = []; $integrationError = null; if ($connection && $etsy->configured()) { try { $receipts = $etsy->receipts($connection)['results'] ?? []; $listings = $etsy->listings($connection)['results'] ?? []; } catch (Throwable $exception) { report($exception); $integrationError = 'Etsy data is temporarily unavailable. Reconnect the shop if this continues.'; } } return view('etsy', compact('connection', 'receipts', 'listings', 'integrationError') + ['configured' => $etsy->configured()]); } public function connect(Request $request, Etsy $etsy): RedirectResponse { abort_unless($request->user()->role === 'admin', 403); if (! $etsy->configured()) { return back()->withErrors(['etsy' => 'Configure the Etsy app key and shared secret first.']); } $state = bin2hex(random_bytes(24)); $verifier = rtrim(strtr(base64_encode(random_bytes(48)), '+/', '-_'), '='); $request->session()->put('etsy_oauth', ['state' => $state, 'verifier' => $verifier, 'started' => time()]); return redirect()->away($etsy->authorizationUrl($state, $verifier)); } public function callback(Request $request, Etsy $etsy): RedirectResponse { abort_unless($request->user()->role === 'admin', 403); $pending = $request->session()->pull('etsy_oauth'); if (! is_array($pending) || time() - ($pending['started'] ?? 0) > 600 || ! is_string($request->query('state')) || ! hash_equals($pending['state'] ?? '', $request->query('state')) || ! is_string($request->query('code'))) { return redirect()->route('etsy.index')->withErrors(['etsy' => 'Etsy connection expired or was not verified. Please try again.']); } try { $connection = $etsy->connect($request->query('code'), $pending['verifier']); return redirect()->route('etsy.index')->with('status', $connection->shop_name.' connected to Etsy.'); } catch (Throwable $exception) { report($exception); return redirect()->route('etsy.index')->withErrors(['etsy' => 'Etsy rejected the connection. Check the app credentials and callback URL.']); } } }