user()->portfolios; return ApiResponse::success($portfolios); } public function store(Request $request) { $validated = $request->validate([ 'name' => 'required|string|max:255', 'domain' => 'required|string|max:255|unique:portfolios,domain', ]); $portfolio = auth()->user()->portfolios()->create($validated); return ApiResponse::success($portfolio, 'Portfolio created', 201); } public function show(Portfolio $portfolio) { $this->authorizeAccess($portfolio); return ApiResponse::success($portfolio); } public function update(Request $request, Portfolio $portfolio) { $this->authorizeAccess($portfolio); $validated = $request->validate([ 'name' => 'sometimes|string|max:255', 'domain' => 'sometimes|string|max:255|unique:portfolios,domain,' . $portfolio->id, ]); $portfolio->update($validated); return ApiResponse::success($portfolio, 'Portfolio updated'); } public function destroy(Portfolio $portfolio) { $this->authorizeAccess($portfolio); $portfolio->delete(); return ApiResponse::success(null, 'Portfolio deleted'); } private function authorizeAccess(Portfolio $portfolio) { if ($portfolio->user_id !== auth()->id()) { abort(403, 'Unauthorized'); } } private function verifyActivation(Portfolio $portfolio) { if (!$portfolio->active) { abort(403, 'Portfolio unpaid'); } } public function upload(Request $request, Portfolio $portfolio) { $this->authorizeAccess($portfolio); $this->verifyActivation($portfolio); $request->validate([ 'file' => 'required|file|max:10240', // Max 10MB ]); $siteName = $portfolio->getAttribute('name'); $siteHost = $portfolio->getAttribute('domain'); $path = $request->file('file')->storeAs( "portfolios/{$siteName}/{$portfolio->id}", 'index.html' ); $portfolio->update([ 'path' => $path, ]); return ApiResponse::success(null, 'ZIP uploaded successfully'); } public function deploy(Request $request, Portfolio $portfolio) { $this->authorizeAccess($portfolio); $siteName = $portfolio->getAttribute('name'); $siteHost = $portfolio->getAttribute('domain'); DeployStaticSiteJob::dispatch($siteName, $siteHost, $portfolio->id); return response()->json([ 'message' => "Async deployment queued for '{$siteName}'." ]); } public function randomPortfolio() { return ApiResponse::success(["host" => Portfolio::inRandomOrder()->first()->domain]); } }