Files
takeone-youtube-clone/app/Http/Controllers/StudioController.php
T
ghassanandClaude Opus 4.7 8c6746e547 feat(studio): /studio content table + bulk visibility / bulk delete
Skeleton for the creator studio surface deferred since Phase 6. The
/studio route lands on a filterable table of the signed-in user's
videos — All / Public / Unlisted / Private / Shorts / Processing-or-
Failed — with headline totals (public / unlisted / private counts,
processing + failed, total views) in a stat strip above.

Each row shows thumbnail + title + stripped description preview +
visibility badge + per-video totals. Row-level checkboxes raise a
toolbar when any row is selected; the toolbar supports:
  - Change visibility across the selection (any of the three visibility
    enums).
  - Delete the selection with a confirm prompt.

Server-side the bulk endpoints owner-filter by Auth::id() so a crafted
request body can't flip or delete anyone else's videos. Response is
JSON { updated | deleted : N } so the page can reload / toast cleanly.

Sidebar now carries a persistent "Studio" link under the You section
alongside History / Liked Videos.

Analytics, stepped upload (Details → Visibility), and schedule remain
future work — this ships the content management surface, nothing else.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-10-21 12:35:47 +03:00

99 lines
3.4 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Video;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
/**
* Creator studio — the content management surface YouTube calls "YouTube
* Studio". A skeleton for now: a filterable table of the signed-in user's
* videos plus a bulk visibility change endpoint. Analytics, stepped upload
* and schedule are future work.
*/
class StudioController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
/**
* The studio dashboard — defaults to the content tab.
*/
public function index(Request $request)
{
$user = Auth::user();
$filter = $request->get('filter', 'all');
$query = Video::where('user_id', $user->id)->latest();
switch ($filter) {
case 'public': $query->where('visibility', 'public'); break;
case 'unlisted': $query->where('visibility', 'unlisted'); break;
case 'private': $query->where('visibility', 'private'); break;
case 'shorts': $query->where('is_shorts', true); break;
case 'draft': $query->whereIn('status', ['pending', 'processing', 'failed']); break;
}
$videos = $query->paginate(24)->withQueryString();
// Headline numbers for the top bar.
$totals = [
'total' => Video::where('user_id', $user->id)->count(),
'public' => Video::where('user_id', $user->id)->where('visibility', 'public')->count(),
'unlisted' => Video::where('user_id', $user->id)->where('visibility', 'unlisted')->count(),
'private' => Video::where('user_id', $user->id)->where('visibility', 'private')->count(),
'processing' => Video::where('user_id', $user->id)->whereIn('status', ['pending', 'processing'])->count(),
'failed' => Video::where('user_id', $user->id)->where('status', 'failed')->count(),
'total_views' => \DB::table('video_views')
->whereIn('video_id', Video::where('user_id', $user->id)->pluck('id'))
->count(),
];
return view('studio.index', [
'videos' => $videos,
'filter' => $filter,
'totals' => $totals,
]);
}
/**
* Bulk visibility change. POSTs { video_ids: [...], visibility: '...' }.
* Guards against setting visibility on videos the user doesn't own, so a
* crafted request can't flip anyone else's content.
*/
public function bulkVisibility(Request $request)
{
$request->validate([
'video_ids' => ['required', 'array', 'min:1'],
'video_ids.*' => ['integer'],
'visibility' => ['required', 'in:public,unlisted,private'],
]);
$updated = Video::whereIn('id', $request->video_ids)
->where('user_id', Auth::id())
->update(['visibility' => $request->visibility]);
return response()->json(['updated' => $updated]);
}
/**
* Bulk delete. Same owner-only guard as above.
*/
public function bulkDelete(Request $request)
{
$request->validate([
'video_ids' => ['required', 'array', 'min:1'],
'video_ids.*' => ['integer'],
]);
$deleted = Video::whereIn('id', $request->video_ids)
->where('user_id', Auth::id())
->delete();
return response()->json(['deleted' => $deleted]);
}
}