Files
ladill-link/app/Http/Controllers/Link/CampaignController.php
T
isaacclad f45fdcd159
Deploy Ladill Link / deploy (push) Successful in 1m26s
Add Campaigns module for grouping short links.
Let accounts organise links by promo or launch, attach or detach links, and view combined click totals from the sidebar.
2026-07-16 20:43:11 +00:00

157 lines
4.9 KiB
PHP

<?php
namespace App\Http\Controllers\Link;
use App\Http\Controllers\Controller;
use App\Models\Campaign;
use App\Models\ShortLink;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\View\View;
class CampaignController extends Controller
{
public function index(Request $request): View
{
$account = ladill_account();
$campaigns = Campaign::query()
->where('user_id', $account->id)
->withCount('shortLinks')
->withSum('shortLinks', 'clicks_total')
->latest()
->paginate(20)
->withQueryString();
$base = Campaign::query()->where('user_id', $account->id);
return view('links.campaigns.index', [
'campaigns' => $campaigns,
'campaignCount' => (clone $base)->count(),
'activeCount' => (clone $base)->where('status', Campaign::STATUS_ACTIVE)->count(),
'linksInCampaigns' => ShortLink::query()
->where('user_id', $account->id)
->whereNotNull('campaign_id')
->count(),
]);
}
public function create(): View
{
return view('links.campaigns.create', [
'campaign' => new Campaign(['status' => Campaign::STATUS_ACTIVE]),
]);
}
public function store(Request $request): RedirectResponse
{
$account = ladill_account();
$data = $this->validated($request);
$campaign = Campaign::create([
...$data,
'user_id' => $account->id,
]);
return redirect()
->route('link.campaigns.show', $campaign)
->with('success', 'Campaign created.');
}
public function show(Campaign $campaign): View
{
$this->authorizeCampaign($campaign);
$links = $campaign->shortLinks()->latest()->get();
$availableLinks = ShortLink::query()
->where('user_id', $campaign->user_id)
->where(function ($q) use ($campaign) {
$q->whereNull('campaign_id')->orWhere('campaign_id', $campaign->id);
})
->orderBy('slug')
->get();
return view('links.campaigns.show', [
'campaign' => $campaign,
'links' => $links,
'availableLinks' => $availableLinks,
'totalClicks' => (int) $links->sum('clicks_total'),
]);
}
public function update(Request $request, Campaign $campaign): RedirectResponse
{
$this->authorizeCampaign($campaign);
$campaign->update($this->validated($request));
return back()->with('success', 'Campaign updated.');
}
public function destroy(Campaign $campaign): RedirectResponse
{
$this->authorizeCampaign($campaign);
ShortLink::query()
->where('campaign_id', $campaign->id)
->update(['campaign_id' => null]);
$campaign->delete();
return redirect()
->route('link.campaigns.index')
->with('success', 'Campaign deleted. Links were unassigned, not removed.');
}
public function attach(Request $request, Campaign $campaign): RedirectResponse
{
$this->authorizeCampaign($campaign);
$validated = $request->validate([
'short_link_ids' => ['required', 'array', 'min:1'],
'short_link_ids.*' => ['integer'],
]);
ShortLink::query()
->where('user_id', $campaign->user_id)
->whereIn('id', $validated['short_link_ids'])
->update(['campaign_id' => $campaign->id]);
return back()->with('success', 'Links added to campaign.');
}
public function detach(Campaign $campaign, ShortLink $link): RedirectResponse
{
$this->authorizeCampaign($campaign);
abort_unless((int) $link->user_id === (int) $campaign->user_id, 403);
abort_unless((int) $link->campaign_id === (int) $campaign->id, 404);
$link->update(['campaign_id' => null]);
return back()->with('success', 'Link removed from campaign.');
}
/** @return array<string, mixed> */
private function validated(Request $request): array
{
$data = $request->validate([
'name' => ['required', 'string', 'max:120'],
'description' => ['nullable', 'string', 'max:2000'],
'status' => ['required', Rule::in(array_keys(Campaign::STATUSES))],
'starts_at' => ['nullable', 'date'],
'ends_at' => ['nullable', 'date', 'after_or_equal:starts_at'],
]);
$data['description'] = $data['description'] ?? null;
$data['starts_at'] = $data['starts_at'] ?? null;
$data['ends_at'] = $data['ends_at'] ?? null;
return $data;
}
private function authorizeCampaign(Campaign $campaign): void
{
abort_unless((int) $campaign->user_id === (int) ladill_account()->id, 403);
}
}