diff --git a/Servers/ArkServer/Dockerfile b/Servers/ArkServer/Dockerfile index a713680..60f834c 100644 --- a/Servers/ArkServer/Dockerfile +++ b/Servers/ArkServer/Dockerfile @@ -26,7 +26,5 @@ RUN sudo -u ark -s RUN chmod +x ./run.sh RUN ulimit -n 100000 RUN /usr/games/steamcmd +force_install_dir /app +login anonymous +app_update 376030 validate +exit -#RUN chmod +x ./ShooterGame/Binaries/Linux/ShooterGameServer - ENTRYPOINT [ "./run.sh" ] \ No newline at end of file diff --git a/Servers/ArkServer/pre-run.sh b/Servers/ArkServer/pre-run.sh deleted file mode 100644 index e69de29..0000000 diff --git a/app/Docker/Container.php b/app/Docker/Container.php index 31b0e8c..a20d7a9 100644 --- a/app/Docker/Container.php +++ b/app/Docker/Container.php @@ -31,7 +31,7 @@ public function start() { try { $response = await($this->browser->post(Docker::endpoint("/containers/" . $this->id . "/start"), [ - "Content-Type" => "text/plain" + "Content-Type" => "text/plain" ])); return json_decode($response->getBody()); } catch (Exception $e) { @@ -39,9 +39,8 @@ public function start() } } - public function restart($context) + public function restart() { - $context = $context ?? [ "onSuccess" => function() {}, "onError" => function() {}]; try { $response = await($this->browser->post( Docker::endpoint("/containers/" . $this->id . "/restart"), @@ -53,9 +52,8 @@ public function restart($context) } } - public function stop($context) + public function stop() { - $context = $context ?? [ "onSuccess" => function() {}, "onError" => function() {}]; try { $response = await($this->browser->post( Docker::endpoint("/containers/" . $this->id . "/stop"), @@ -67,9 +65,8 @@ public function stop($context) } } - public function kill($context) + public function kill() { - $context = $context ?? [ "onSuccess" => function() {}, "onError" => function() {}]; try { $response = await($this->browser->post( Docker::endpoint("/containers/" . $this->id . "/kill"), diff --git a/app/Http/Controllers/Auth/AuthenticatedSessionController.php b/app/Http/Controllers/Auth/AuthenticatedSessionController.php index d44fe97..628a33b 100644 --- a/app/Http/Controllers/Auth/AuthenticatedSessionController.php +++ b/app/Http/Controllers/Auth/AuthenticatedSessionController.php @@ -33,7 +33,7 @@ public function store(LoginRequest $request): RedirectResponse $request->session()->regenerate(); - return redirect()->intended(route('dashboard', absolute: false)); + return redirect()->intended(route('home', absolute: false)); } /** diff --git a/app/Http/Controllers/Auth/ConfirmablePasswordController.php b/app/Http/Controllers/Auth/ConfirmablePasswordController.php index d2b1f14..af15eec 100644 --- a/app/Http/Controllers/Auth/ConfirmablePasswordController.php +++ b/app/Http/Controllers/Auth/ConfirmablePasswordController.php @@ -36,6 +36,6 @@ public function store(Request $request): RedirectResponse $request->session()->put('auth.password_confirmed_at', time()); - return redirect()->intended(route('dashboard', absolute: false)); + return redirect()->intended(route('home', absolute: false)); } } diff --git a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php index f64fa9b..03dc4a5 100644 --- a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php +++ b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php @@ -14,7 +14,7 @@ class EmailVerificationNotificationController extends Controller public function store(Request $request): RedirectResponse { if ($request->user()->hasVerifiedEmail()) { - return redirect()->intended(route('dashboard', absolute: false)); + return redirect()->intended(route('home', absolute: false)); } $request->user()->sendEmailVerificationNotification(); diff --git a/app/Http/Controllers/Auth/EmailVerificationPromptController.php b/app/Http/Controllers/Auth/EmailVerificationPromptController.php index b42e0d5..99e15ee 100644 --- a/app/Http/Controllers/Auth/EmailVerificationPromptController.php +++ b/app/Http/Controllers/Auth/EmailVerificationPromptController.php @@ -16,7 +16,7 @@ class EmailVerificationPromptController extends Controller public function __invoke(Request $request): RedirectResponse|Response { return $request->user()->hasVerifiedEmail() - ? redirect()->intended(route('dashboard', absolute: false)) + ? redirect()->intended(route('home', absolute: false)) : Inertia::render('Auth/VerifyEmail', ['status' => session('status')]); } } diff --git a/app/Http/Controllers/Auth/RegisteredUserController.php b/app/Http/Controllers/Auth/RegisteredUserController.php index 53a546b..f84c23e 100644 --- a/app/Http/Controllers/Auth/RegisteredUserController.php +++ b/app/Http/Controllers/Auth/RegisteredUserController.php @@ -46,6 +46,6 @@ public function store(Request $request): RedirectResponse Auth::login($user); - return redirect(route('dashboard', absolute: false)); + return redirect(route('home', absolute: false)); } } diff --git a/app/Http/Controllers/Auth/VerifyEmailController.php b/app/Http/Controllers/Auth/VerifyEmailController.php index 784765e..5b61d4c 100644 --- a/app/Http/Controllers/Auth/VerifyEmailController.php +++ b/app/Http/Controllers/Auth/VerifyEmailController.php @@ -15,13 +15,13 @@ class VerifyEmailController extends Controller public function __invoke(EmailVerificationRequest $request): RedirectResponse { if ($request->user()->hasVerifiedEmail()) { - return redirect()->intended(route('dashboard', absolute: false).'?verified=1'); + return redirect()->intended(route('home', absolute: false).'?verified=1'); } if ($request->user()->markEmailAsVerified()) { event(new Verified($request->user())); } - return redirect()->intended(route('dashboard', absolute: false).'?verified=1'); + return redirect()->intended(route('home', absolute: false).'?verified=1'); } } diff --git a/app/Http/Controllers/ServerController.php b/app/Http/Controllers/ServerController.php index ba06b2a..56f8d67 100644 --- a/app/Http/Controllers/ServerController.php +++ b/app/Http/Controllers/ServerController.php @@ -10,6 +10,7 @@ use App\Models\ExposedPort; use App\Models\Server; use App\Models\Service; +use Carbon\Carbon; use Exception; use Illuminate\Support\Facades\Auth; use Inertia\Inertia; @@ -17,13 +18,48 @@ class ServerController extends Controller { + public function start(Request $request) + { + $server = Server::where("uuid", $request->id)->first(); + if($server->status_id >= 3) { + try { + $container = new Container($server->container); + $container->start(); + $server->update([ + "status_id" => 1, + "start" => Carbon::now() + ]); + return redirect()->back()->withErrors([ "message" => "Serveur lancé avec succès. Attendez quelque seconds avant de vous connectez." ]); + } catch(Exception $e) { return redirect()->back()->withErrors([ "error" => "Impossible de démarré le serveur." ]); } + + } else { return redirect()->back()->withErrors([ "error" => "Serveur déjà ou entrain de démarré." ]); } + } + + public function stop(Request $request) + { + $server = Server::where("uuid", $request->id)->first(); + if($server->status_id < 3) { + try { + $server->update([ + "status_id" => 3, + "end" => Carbon::now() + ]); + $container = new Container($server->container); + $container->stop(); + return redirect()->back()->withErrors([ "message" => "Serveur arrêté avec succès. Merci de votre visite." ]); + } catch(Exception $e) { return redirect()->back()->withErrors([ "error" => "Impossible de d'arrêter le serveur." ]); } + + } else { return redirect()->back()->withErrors([ "error" => "Serveur déjà ou entrain de s'arrêter." ]); } + } + /** * Display a listing of the resource. */ public function index() { return Inertia::render("Server/Index", [ - "servers" => Server::all()->jsonSerialize(), + "banner" => "/img/banner.gif", + "servers" => (Auth::user()->admin ? Server::orderBy("start", "DESC")->orderBy("end", "DESC")->get() : Server::where("user_id", Auth::user()->id)->get())->jsonSerialize(), ]); } @@ -33,6 +69,7 @@ public function index() public function create() { return Inertia::render('Server/Create', [ + "banner" => "/img/banner.jpg", "services" => Service::all() ]); } @@ -45,9 +82,14 @@ public function store(Request $request) $request->validate([ "name" => "required|string", "service" => "required|string", + "launch" => "nullable" ]); + + $user = Auth::user(); + if(!$user->admin && count($user->server) >= 2) return redirect()->back()->withErrors(["error" => "Vous avez déjà trop de servers. Veillez en supprimer un!"]); - $service = Service::where("uuid", $request->service)->firstOrFail(); + $service = Service::where("uuid", $request->service)->first(); + if(!$service) return redirect()->back()->withErrors(["error" => "Impossible de trouver ce service!"]); $server = Server::create([ "uuid" => Str::uuid(), "name" => preg_replace('/[^a-zA-Z0-9_.-]/', '', $request->name), @@ -55,8 +97,27 @@ public function store(Request $request) "status_id" => 3, "user_id" => Auth::user()->id ]); - dispatch(new InitServer($server)); - return redirect(route("servers.index")); + + $config = config($server->service->config); + $ports = explode("|", $server->service->ports); + + for ($i = 0; $i < count($ports); $i++) { + $port = ExposedPort::where("usable", true)->first(); + if(!$port) { + $server->exposedPorts()->update([ "usable" => true ]); + $server->exposedPorts()->detach(); + $server->delete(); + return redirect()->back()->withErrors(["error" => "Aucune place libre pour votre server, réessayer plus tard."]); + } + $server->exposedPorts()->attach($port->id); + $port->update(["usable" => false]); + + $config["ExposedPorts"][$ports[$i] . "/" . $server->service->protocol] = (object)[]; + $config["HostConfig"]["PortBindings"][$ports[$i] . "/" . $server->service->protocol] = [[ "HostPort" => "" . $port->number ]]; + } + + dispatch(new InitServer($server, $config, $request->launch ? true : false)); + return redirect(route("servers.index"))->withErrors([ "message" => "Serveur créer avec succès" . ($request->launch ? " et devrait se lancer d'une minute à l'autre." : ".") ]); } /** @@ -65,32 +126,52 @@ public function store(Request $request) public function show(Request $request) { $server = Server::where("uuid", $request->id)->firstOrFail(); + return Inertia::render("Server/Show", [ - "server" => $server + "banner" => "/img/banner.webp", + "server" => $server->jsonSerialize() ]); } /** - * Show the form for editing the specified resource. + * Update the specified resource in storage. */ - public function edit(string $id) + public function update(Request $request) { - // + $request->validate([ + "name" => "required|string|max:25", + ]); + + $server = Server::where("uuid", $request->id)->first(); + $server->update([ + "name" => preg_replace('/[^a-zA-Z0-9_.-]/', '', $request->name) + ]); + return redirect()->back()->withErrors(["message" => "Nom changé avec succès."]); } - /** - * Update the specified resource in storage. - */ - public function update(Request $request, string $id) + public function makePublic(Request $request) { - // + $server = Server::where("uuid", $request->id)->first(); + $server->update([ + "public" => !$server->public, + ]); + return redirect()->back()->withErrors(["message" => $server->public ? "Server rendu publiquement accéssible." : "Server rendu privé."]); } /** * Remove the specified resource from storage. */ - public function destroy(string $id) + public function destroy(Request $request) { - // + $server = Server::where("uuid", $request->id)->first(); + try { + $container = new Container($server->container); + $data = $container->inspect()->State; + if($data->Running || $data->Paused || $data->Restarting) $container->kill(); + } catch(Exception) { return redirect()->back()->withErrors(["error" => "Problème pour éteindre le serveur. Réessayer!"]); } + $server->exposedPorts()->update([ "usable" => true ]); + $server->exposedPorts()->detach(); + $server->delete(); + return redirect(route("servers.index"))->withErrors(["message" => "Server supprimer avec succès."]); } } diff --git a/app/Http/Middleware/ResourceRules.php b/app/Http/Middleware/ResourceRules.php new file mode 100644 index 0000000..cda1133 --- /dev/null +++ b/app/Http/Middleware/ResourceRules.php @@ -0,0 +1,25 @@ +id)->first(); + if(!$server) return redirect(route("servers.index"))->withErrors(["error" => "Impossible de trouver ce server!"]); + if(Auth::user()->id == $server->id || Auth::user()->admin) return $next($request); + return redirect(route("servers.index"))->withErrors(["error" => "Vous n'avez d'autorisation d'access a se serveur!"]); + } +} diff --git a/app/Jobs/InitServer.php b/app/Jobs/InitServer.php index f5bec01..2d3fbac 100644 --- a/app/Jobs/InitServer.php +++ b/app/Jobs/InitServer.php @@ -15,12 +15,16 @@ class InitServer implements ShouldQueue use Queueable; protected $server; + protected $config; + protected $launch; /** * Create a new job instance. */ - public function __construct($server) + public function __construct($server, $config, $launch) { $this->server = $server; + $this->launch = $launch; + $this->config = $config; $server->update(["status_id" => 2]); } @@ -30,24 +34,22 @@ public function __construct($server) public function handle(): void { try { - $config = config($this->server->service->config); - $ports = explode("|", $this->server->service->ports); - for ($i = 0; $i < count($ports); $i++) { - $port = ExposedPort::where("usable", true)->first(); - if(!$port) throw new Exception("All ports are used, please try later."); - $this->server->exposedPorts()->attach($port->id); - $port->update(["usable" => false]); - $config["ExposedPorts"][$ports[$i] . "/" . $this->server->service->protocol] = (object)[]; - $config["HostConfig"]["PortBindings"][$ports[$i] . "/" . $this->server->service->protocol] = [[ "HostPort" => "" . $port->number ]]; + $container = Container::create($this->server->name . Str::random(5), $this->config); + if($this->launch) { + $container->start(); + $this->server->update([ + "container" => $container->getId(), + "status_id" => 1, + "start" => now(), + "end" => now() + ]); + } else { + $this->server->update([ + "container" => $container->getId(), + "status_id" => 3, + "end" => now() + ]); } - Log::info(json_encode($config, JSON_UNESCAPED_SLASHES)); - $container = Container::create($this->server->name . Str::random(5), $config); - $container->start(); - $this->server->update([ - "container" => $container->getId(), - "status_id" => 1, - "start" => now() - ]); }catch(Exception $e) { $this->fail($e); } @@ -57,9 +59,8 @@ public function fail($e): void { $this->server->update([ "status_id" => 4, - "end" => now() ]); $this->server->exposedPorts()->detach(); - Log::info($e->getResponse()->getBody()); + Log::info(((object)$e)->getResponse()->getBody()); } } diff --git a/app/Models/Server.php b/app/Models/Server.php index 5d1d13d..219a823 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -12,6 +12,7 @@ class Server extends Model "container", "start", "end", + "public", "service_id", "user_id", "status_id", @@ -24,6 +25,7 @@ public function jsonSerialize(): mixed 'name' => $this->name, "start" => $this->start, "end" => $this->end, + "public" => $this->public, "service" => $this->service, "user" => $this->user, "status" => $this->status, diff --git a/app/Models/User.php b/app/Models/User.php index ca91d2b..e7da18e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -21,6 +21,8 @@ class User extends Authenticatable 'name', 'email', 'password', + 'email_verified_at', + 'admin' ]; public function servers() diff --git a/database/migrations/2025_02_14_231846_create_server_statuses_table.php b/database/migrations/2025_02_14_231846_create_server_statuses_table.php index b921214..92d5d42 100644 --- a/database/migrations/2025_02_14_231846_create_server_statuses_table.php +++ b/database/migrations/2025_02_14_231846_create_server_statuses_table.php @@ -34,6 +34,11 @@ public function up(): void "message" => "", ]); + Status::create([ + "title" => "Stopping", + "message" => "", + ]); + Status::create([ "title" => "Failed", "message" => "", diff --git a/database/migrations/2025_02_14_234835_create_servers_table.php b/database/migrations/2025_02_14_234835_create_servers_table.php index f9dab81..759b5a8 100644 --- a/database/migrations/2025_02_14_234835_create_servers_table.php +++ b/database/migrations/2025_02_14_234835_create_servers_table.php @@ -16,6 +16,7 @@ public function up(): void $table->uuid("uuid"); $table->string("container", 511)->nullable(); $table->string("name"); + $table->boolean("public")->default(false); $table->dateTime("start")->nullable(); $table->dateTime("end")->nullable(); $table->unsignedBigInteger("service_id"); diff --git a/public/icons/lock.svg b/public/icons/lock.svg new file mode 100644 index 0000000..11fdae0 --- /dev/null +++ b/public/icons/lock.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/public/icons/logout.svg b/public/icons/logout.svg new file mode 100644 index 0000000..cd07bd9 --- /dev/null +++ b/public/icons/logout.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/public/img/banner.gif b/public/img/banner.gif new file mode 100644 index 0000000..d9463dc Binary files /dev/null and b/public/img/banner.gif differ diff --git a/public/img/banner.webp b/public/img/banner.webp new file mode 100644 index 0000000..0f88515 Binary files /dev/null and b/public/img/banner.webp differ diff --git a/resources/css/app.css b/resources/css/app.css index 3e1fa01..9be7cda 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -49,4 +49,17 @@ .glow-on-hover { .glow-on-hover:hover { transform: scale(1.05); box-shadow: 0 0 2px 2px rgba(51, 51, 51, 0.8); +} + +@keyframes grow { +from { + width: 0%; +} + +to { + width: 100%; +} +} +.grow { + animation: grow 6s linear forwards; } \ No newline at end of file diff --git a/resources/js/Layouts/AuthenticatedLayout.vue b/resources/js/Layouts/AuthenticatedLayout.vue index 97c58e0..224c42c 100644 --- a/resources/js/Layouts/AuthenticatedLayout.vue +++ b/resources/js/Layouts/AuthenticatedLayout.vue @@ -22,7 +22,7 @@ const showingNavigationDropdown = ref(false);
- + @@ -34,7 +34,7 @@ const showingNavigationDropdown = ref(false); class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex" > Dashboard @@ -141,7 +141,7 @@ const showingNavigationDropdown = ref(false); >
Dashboard diff --git a/resources/js/Layouts/Layout.vue b/resources/js/Layouts/Layout.vue index 6ecd09a..0e5b4b2 100644 --- a/resources/js/Layouts/Layout.vue +++ b/resources/js/Layouts/Layout.vue @@ -1,6 +1,33 @@ \ No newline at end of file diff --git a/resources/js/Pages/Auth/Login.vue b/resources/js/Pages/Auth/Login.vue index 43b7c91..8ec3b19 100644 --- a/resources/js/Pages/Auth/Login.vue +++ b/resources/js/Pages/Auth/Login.vue @@ -1,6 +1,6 @@ diff --git a/resources/js/Pages/Home.vue b/resources/js/Pages/Home.vue index 1fc3c6f..fd278e6 100644 --- a/resources/js/Pages/Home.vue +++ b/resources/js/Pages/Home.vue @@ -1,10 +1,15 @@