user(); if (!$user) { return response()->json([ 'message' => 'Utilizador não autenticado', 'data' => null, ], 401); } $search = trim((string) $request->query('search', '')); $categoryId = $request->query('category'); $watched = $request->query('watched'); $perPage = $request->query('per_page', 9); $query = Video::select(['id', 'title', 'thumbnail', 'is_active']) ->with([ 'categories:id,name', 'views' => function ($q) use ($user) { $q->select('id', 'video_id', 'user_id') ->where('user_id', $user->id); } ]) ->when($search !== '', function ($q) use ($search) { $q->where(function ($sub) use ($search) { $sub->where('title', 'like', "%{$search}%") ->orWhere('tags', 'like', "%{$search}%"); }); }) ->when($categoryId, function ($q) use ($categoryId) { $q->whereHas('categories', function ($c) use ($categoryId) { $c->where('categories.id', $categoryId); }); }) ->when($user->role_id !== 1, function ($q) { $q->where('is_active', true); }) ->when($watched !== null, function ($q) use ($watched, $user) { if ((int) $watched === 1) { $q->whereHas('views', function ($v) use ($user) { $v->where('user_id', $user->id); }); } if ((int) $watched === 0) { $q->whereDoesntHave('views', function ($v) use ($user) { $v->where('user_id', $user->id); }); } }) ->orderByRaw(' CASE WHEN EXISTS ( SELECT 1 FROM video_views WHERE video_views.video_id = videos.id AND video_views.user_id = ? ) THEN 1 ELSE 0 END ASC, videos.order ASC ', [$user->id]) ->paginate($perPage); $query->getCollection()->transform(function ($video) { return [ 'id' => $video->id, 'title' => $video->title, 'thumbnail' => $video->thumbnail, 'is_active' => $video->is_active, 'categories' => $video->categories, 'watched' => $video->views->isNotEmpty(), ]; }); return response()->json([ 'message' => 'Vídeos obtidos com sucesso', 'data' => $query->items(), 'meta' => [ 'current_page' => $query->currentPage(), 'last_page' => $query->lastPage(), 'per_page' => $query->perPage(), 'total' => $query->total(), ], ]); } public function nextVideos() { $user = auth()->user(); if (!$user) { return response()->json([ 'message' => 'Não autenticado', ], 401); } $videos = Video::select(['id', 'title', 'thumbnail', 'is_active', 'order']) ->with(['categories:id,name']) // 👇 regra base: vídeos não vistos ->whereDoesntHave('views', function ($q) use ($user) { $q->where('user_id', $user->id); }) // 👇 users normais não veem inativos ->when($user->role_id !== 1, function ($q) { $q->where('is_active', true); }) ->orderBy('order', 'asc') ->limit(3) ->get() ->map(function ($video) { return [ 'id' => $video->id, 'title' => $video->title, 'thumbnail' => $video->thumbnail, 'is_active' => $video->is_active, 'categories' => $video->categories, 'watched' => false, // aqui já sabes que não foram vistos ]; }); return response()->json([ 'message' => 'Dashboard videos', 'data' => $videos, ]); } public function search(Request $request) { $user = auth()->user(); $search = trim((string) $request->query('search', '')); $videos = Video::select(['id', 'title', 'thumbnail', 'is_active']) ->with([ 'categories:id,name', 'views' => function ($query) use ($user) { $query->select('id', 'video_id', 'user_id') ->where('user_id', $user->id); } ]) ->when($user->role_id !== 1, function ($query) { $query->where('is_active', true); }) ->where(function ($query) use ($search) { $query->where('title', 'like', "%{$search}%") ->orWhere('tags', 'like', "%{$search}%"); }) ->limit(20) ->get() ->map(function ($video) { return [ 'id' => $video->id, 'title' => $video->title, 'thumbnail' => $video->thumbnail, 'is_active' => $video->is_active, 'categories' => $video->categories, 'watched' => $video->views->isNotEmpty(), ]; }); return response()->json([ 'message' => 'Resultados obtidos com sucesso', 'data' => $videos, ]); } public function videosLength() { $user = auth()->user(); $userID = $user->id; if ($user->role_id !== 1) { $videos = Video::select('id')->with('views')->where('is_active', true)->count(); $videosWatched = Video::with('views')->where('is_active', true)->whereHas('views', function ($query) use ($userID) { $query->where('user_id', $userID); })->count(); } else { $videos = Video::select('id')->with('views')->where('is_active', true)->count(); } return response()->json([ 'message' => 'Vídeos ativos obtidos com sucesso', 'data' => [ 'videos' => $videos, 'videosWatched' => $videosWatched ?? 0, ], 'errors' => null, ], 200); } public function getVideo($id) { $user = auth()->user(); if (!$user) { return response()->json([ 'message' => 'Utilizador não autenticado', 'data' => null, 'errors' => null, ], 404); } $userID = $user->id; if ($user->role_id !== 1) { /* $video = Video::with('categories')->where('is_active', true)->find($id); */ $video = Video::with([ 'categories' => function ($query) use ($userID) { $query->where('is_active', true); }, 'views' => function ($query) use ($userID) { $query->where('user_id', $userID); } ])->find($id); /* Para não mostrar vídeos inactivos para utilizadores não administradores */ if (!$video || $video->is_active === false) { return response()->json([ 'message' => 'Acesso negado', 'data' => null, 'errors' => null, ], 404); } } $video = Video::with('categories')->find($id); if ($video) { $video->url = Storage::url($video->url); $video->thumbnail = Storage::url($video->thumbnail); return response()->json([ 'message' => 'Vídeo obtido com sucesso', 'data' => [ 'id' => $video->id, 'title' => $video->title, 'description' => $video->description, 'url' => $video->url, 'thumbnail' => $video->thumbnail, 'duration' => $video->duration, 'tags' => $video->tags, 'order' => $video->order, 'categories' => $video->categories->map(function ($category) { return [ 'id' => $category->id, 'name' => $category->name, ]; })->values(), 'is_active' => $video->is_active, 'watched' => $video->views->isNotEmpty(), ], 'errors' => null, ], 200); } else { return response()->json([ 'message' => 'Vídeo não encontrado', 'data' => null, 'errors' => null, ], 404); } } public function create(CreateVideoRequest $request) { $user = auth()->user(); if (!$user) { return response()->json([ 'message' => 'Utilizador não autenticado', 'data' => null, 'errors' => null, ], 404); } $validated = $request->validated(); $videoPath = $request->file('url')->store('videos', 'public'); $thumbnailPath = $request->file('thumbnail')->store('thumbnails', 'public'); $video = Video::create([ 'title' => $validated['title'], 'description' => $validated['description'], 'url' => $videoPath, 'thumbnail' => $thumbnailPath, 'duration' => $validated['duration'] ?? '00:00', 'tags' => $validated['tags'], 'order' => $validated['order'], ]); if ($request->filled('category_ids')) { $video->categories()->sync($request->input('category_ids')); } $baseUrl = $request->getSchemeAndHttpHost(); return response()->json([ 'message' => 'Vídeo adicionado com sucesso', 'data' => [ 'id' => $video->id, 'title' => $video->title, 'description' => $video->description, 'url' => $baseUrl . Storage::url($video->url), 'thumbnail' => $baseUrl . Storage::url($video->thumbnail), 'duration' => $video->duration, 'tags' => $video->tags, 'order' => $video->order, 'categories' => $video->categories->pluck('name'), 'is_active' => $video->is_active, ], 'errors' => null, ], 201); } public function update(UpdateVideoRequest $request, $id) { $user = auth()->user(); if (!$user) { return response()->json([ 'message' => 'Utilizador não autenticado', 'data' => null, 'errors' => null, ], 404); } $videoToUpdate = Video::find($id); if (!$videoToUpdate) { return response()->json([ 'message' => 'Vídeo não encontrado', 'data' => null, 'errors' => null, ], 404); } $validated = $request->validated(); if ($request->hasFile('thumbnail')) { // Apagar thumbnail antiga if ($videoToUpdate->thumbnail && Storage::disk('public')->exists($videoToUpdate->thumbnail)) { Storage::disk('public')->delete($videoToUpdate->thumbnail); } $validated['thumbnail'] = $request->file('thumbnail')->store('thumbnails', 'public'); } try { $videoToUpdate->update([ 'title' => $validated['title'] ?? $videoToUpdate->title, 'description' => $validated['description'] ?? $videoToUpdate->description, 'tags' => $validated['tags'] ?? $videoToUpdate->tags, 'thumbnail' => $validated['thumbnail'] ?? $videoToUpdate->thumbnail, 'is_active' => array_key_exists('is_active', $validated) ? $validated['is_active'] : $videoToUpdate->is_active, 'order' => $validated['order'] ?? $videoToUpdate->order, ]); if ($request->has('category_ids')) { $videoToUpdate->categories()->sync($request->input('category_ids')); } return response()->json([ 'message' => 'Dados do vídeo atualizados com sucesso', 'data' => $videoToUpdate->load('categories'), 'errors' => null, ], 200); } catch (\Throwable $th) { return response()->json([ 'message' => 'Não foi possível atualizar o vídeo', 'data' => null, 'errors' => null, ], 500); } } public function destroy($id) { $user = auth()->user(); if (!$user) { return response()->json([ 'message' => 'Utilizador não autenticado', 'data' => null, 'errors' => null, ], 404); } $video = Video::find($id); if (!$video) { return response()->json([ 'message' => 'Vídeo não encontrado', 'data' => null, 'errors' => null, ], 404); } $video->delete(); return response()->json([ 'message' => 'Vídeo apagado com sucesso', 'data' => null, 'errors' => null, ], 200); } }