where('user_id', $account->id) ->latest() ->paginate(20); return view('links.index', [ 'links' => $links, 'canCreate' => $this->billing->canCreate($account), 'pricePerLink' => \App\Models\LinkWallet::pricePerLink(), ]); } public function create(): View { $account = ladill_account(); return view('links.create', [ 'canCreate' => $this->billing->canCreate($account), 'pricePerLink' => \App\Models\LinkWallet::pricePerLink(), ]); } public function store(Request $request): RedirectResponse { $validated = $request->validate([ 'destination_url' => ['required', 'string', 'max:2048'], 'label' => ['nullable', 'string', 'max:120'], 'custom_slug' => ['nullable', 'string', 'max:20', 'regex:/^[a-z0-9][a-z0-9-]{1,18}[a-z0-9]$/'], 'expires_at' => ['nullable', 'date', 'after:now'], ]); try { $link = $this->links->create(ladill_account(), $validated); } catch (RuntimeException $e) { return back()->withInput()->withErrors(['balance' => $e->getMessage()]); } return redirect() ->route('user.links.show', $link) ->with('success', 'Short link created.'); } public function show(ShortLink $link): View { $this->authorizeLink($link); return view('links.show', [ 'link' => $link, 'recentClicks' => $link->clicks()->latest('clicked_at')->limit(20)->get(), ]); } public function update(Request $request, ShortLink $link): RedirectResponse { $this->authorizeLink($link); $validated = $request->validate([ 'destination_url' => ['sometimes', 'required', 'string', 'max:2048'], 'label' => ['nullable', 'string', 'max:120'], 'is_active' => ['sometimes', 'boolean'], 'expires_at' => ['nullable', 'date'], ]); try { $this->links->update($link, $validated); } catch (RuntimeException $e) { return back()->withInput()->withErrors(['destination_url' => $e->getMessage()]); } return back()->with('success', 'Link updated.'); } public function destroy(ShortLink $link): RedirectResponse { $this->authorizeLink($link); $link->delete(); return redirect()->route('user.links.index')->with('success', 'Link deleted.'); } public function checkSlug(Request $request): \Illuminate\Http\JsonResponse { $slug = strtolower((string) $request->query('slug', '')); $taken = $slug !== '' && ShortLink::where('slug', $slug)->exists(); return response()->json(['available' => ! $taken]); } private function authorizeLink(ShortLink $link): void { if ($link->user_id !== ladill_account()->id) { abort(403); } } }