From e841c385730bf444e584ce592d50c95f8e25df06 Mon Sep 17 00:00:00 2001 From: unurled Date: Thu, 3 Jul 2025 22:16:45 +0200 Subject: [PATCH] Add octan and add team (WIP) --- .gitignore | 4 + Dockerfile | 8 + app/Http/Controllers/TournamentController.php | 33 +++ composer.json | 1 + composer.lock | 263 +++++++++++++++++- config/octane.php | 224 +++++++++++++++ ...22_121731_create_user_permission_table.php | 31 --- ...22_141254_create_permission_user_table.php | 2 +- package.json | 2 +- phpunit.xml | 3 +- resources/js/pages/tournaments/Show.svelte | 43 ++- routes/api.php | 3 + 12 files changed, 575 insertions(+), 42 deletions(-) create mode 100644 Dockerfile create mode 100644 config/octane.php delete mode 100644 database/migrations/2025_06_22_121731_create_user_permission_table.php diff --git a/.gitignore b/.gitignore index 8aae99b..b8c0974 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,7 @@ yarn-error.log /.vscode /.zed .DS_Store + +**/caddy +frankenphp +frankenphp-worker.php diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a6e4967 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM dunglas/frankenphp + +RUN install-php-extensions \ + pcntl + +COPY . /app + +ENTRYPOINT ["php", "artisan", "octane:frankenphp"] diff --git a/app/Http/Controllers/TournamentController.php b/app/Http/Controllers/TournamentController.php index 462744e..a95041f 100644 --- a/app/Http/Controllers/TournamentController.php +++ b/app/Http/Controllers/TournamentController.php @@ -200,4 +200,37 @@ class TournamentController extends Controller return redirect()->route('home') ->with('success', 'Tournament deleted successfully!'); } + + public function addTeam(Competition $tournament, Request $request) + { + // Check if user is tournament owner + if ($tournament->owner != Auth::id()) { + return redirect()->back()->with('error', 'You are not authorized to add a team to this tournament.'); + } + + // Validate the request data + $validator = Validator::make($request->all(), [ + 'team_id' => 'required|exists:teams,id', + ]); + + if ($validator->fails()) { + return redirect()->back()->withErrors($validator)->withInput(); + } + + // Add the team + $team = Team::find($request->team_id); + // if it doesn't exist, create new team + // + if (!$team) { + $team = new Team(); + $team->name = $request->team_name; + $team->save(); + } + $tournament->teams()->attach($team->id); + + + + return redirect()->route('tournaments.show', $tournament->id) + ->with('success', 'Team added successfully!'); + } } diff --git a/composer.json b/composer.json index f1a83c4..b2f93f7 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "php": "^8.2", "inertiajs/inertia-laravel": "^2.0.2", "laravel/framework": "^12.16.0", + "laravel/octane": "^2.10", "laravel/socialite": "^5.21", "laravel/tinker": "^2.10.1", "socialiteproviders/keycloak": "^5.3", diff --git a/composer.lock b/composer.lock index 5e905e8..2632dcb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1a44cdb1a493ed3bfbcf2336ae26c0bf", + "content-hash": "bd02b3c2ddadea250049517b0d891770", "packages": [ { "name": "brick/math", @@ -1185,6 +1185,94 @@ }, "time": "2025-04-10T15:08:36+00:00" }, + { + "name": "laminas/laminas-diactoros", + "version": "3.6.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "b068eac123f21c0e592de41deeb7403b88e0a89f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/b068eac123f21c0e592de41deeb7403b88e0a89f", + "reference": "b068eac123f21c0e592de41deeb7403b88e0a89f", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0" + }, + "conflict": { + "amphp/amp": "<2.6.4" + }, + "provide": { + "psr/http-factory-implementation": "^1.0", + "psr/http-message-implementation": "^1.1 || ^2.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-gd": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^2.2.0", + "laminas/laminas-coding-standard": "~3.0.0", + "php-http/psr7-integration-tests": "^1.4.0", + "phpunit/phpunit": "^10.5.36", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\Diactoros", + "config-provider": "Laminas\\Diactoros\\ConfigProvider" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-17", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2025-05-05T16:03:34+00:00" + }, { "name": "laravel/framework", "version": "v12.19.3", @@ -1400,6 +1488,96 @@ }, "time": "2025-06-18T12:56:23+00:00" }, + { + "name": "laravel/octane", + "version": "v2.10.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/octane.git", + "reference": "62bf04dcb471e7d91c8aeda9b4e7376a75000ee5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/octane/zipball/62bf04dcb471e7d91c8aeda9b4e7376a75000ee5", + "reference": "62bf04dcb471e7d91c8aeda9b4e7376a75000ee5", + "shasum": "" + }, + "require": { + "laminas/laminas-diactoros": "^3.0", + "laravel/framework": "^10.10.1|^11.0|^12.0", + "laravel/prompts": "^0.1.24|^0.2.0|^0.3.0", + "laravel/serializable-closure": "^1.3|^2.0", + "nesbot/carbon": "^2.66.0|^3.0", + "php": "^8.1.0", + "symfony/console": "^6.0|^7.0", + "symfony/psr-http-message-bridge": "^2.2.0|^6.4|^7.0" + }, + "conflict": { + "spiral/roadrunner": "<2023.1.0", + "spiral/roadrunner-cli": "<2.6.0", + "spiral/roadrunner-http": "<3.3.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.6.1", + "inertiajs/inertia-laravel": "^1.3.2|^2.0", + "laravel/scout": "^10.2.1", + "laravel/socialite": "^5.6.1", + "livewire/livewire": "^2.12.3|^3.0", + "mockery/mockery": "^1.5.1", + "nunomaduro/collision": "^6.4.0|^7.5.2|^8.0", + "orchestra/testbench": "^8.21|^9.0|^10.0", + "phpstan/phpstan": "^2.1.7", + "phpunit/phpunit": "^10.4|^11.5", + "spiral/roadrunner-cli": "^2.6.0", + "spiral/roadrunner-http": "^3.3.0" + }, + "bin": [ + "bin/roadrunner-worker", + "bin/swoole-server" + ], + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Octane": "Laravel\\Octane\\Facades\\Octane" + }, + "providers": [ + "Laravel\\Octane\\OctaneServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Octane\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Supercharge your Laravel application's performance.", + "keywords": [ + "frankenphp", + "laravel", + "octane", + "roadrunner", + "swoole" + ], + "support": { + "issues": "https://github.com/laravel/octane/issues", + "source": "https://github.com/laravel/octane" + }, + "time": "2025-06-16T13:44:31+00:00" + }, { "name": "laravel/prompts", "version": "v0.3.5", @@ -5553,6 +5731,89 @@ ], "time": "2025-04-17T09:11:12+00:00" }, + { + "name": "symfony/psr-http-message-bridge", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/psr-http-message-bridge.git", + "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/03f2f72319e7acaf2a9f6fcbe30ef17eec51594f", + "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/http-message": "^1.0|^2.0", + "symfony/http-foundation": "^6.4|^7.0" + }, + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "nyholm/psr7": "^1.1", + "php-http/discovery": "^1.15", + "psr/log": "^1.1.4|^2|^3", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\PsrHttpMessage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "PSR HTTP message bridge", + "homepage": "https://symfony.com", + "keywords": [ + "http", + "http-message", + "psr-17", + "psr-7" + ], + "support": { + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-26T08:57:56+00:00" + }, { "name": "symfony/routing", "version": "v7.3.0", diff --git a/config/octane.php b/config/octane.php new file mode 100644 index 0000000..8cfba01 --- /dev/null +++ b/config/octane.php @@ -0,0 +1,224 @@ + env('OCTANE_SERVER', 'roadrunner'), + + /* + |-------------------------------------------------------------------------- + | Force HTTPS + |-------------------------------------------------------------------------- + | + | When this configuration value is set to "true", Octane will inform the + | framework that all absolute links must be generated using the HTTPS + | protocol. Otherwise your links may be generated using plain HTTP. + | + */ + + 'https' => env('OCTANE_HTTPS', false), + + /* + |-------------------------------------------------------------------------- + | Octane Listeners + |-------------------------------------------------------------------------- + | + | All of the event listeners for Octane's events are defined below. These + | listeners are responsible for resetting your application's state for + | the next request. You may even add your own listeners to the list. + | + */ + + 'listeners' => [ + WorkerStarting::class => [ + EnsureUploadedFilesAreValid::class, + EnsureUploadedFilesCanBeMoved::class, + ], + + RequestReceived::class => [ + ...Octane::prepareApplicationForNextOperation(), + ...Octane::prepareApplicationForNextRequest(), + // + ], + + RequestHandled::class => [ + // + ], + + RequestTerminated::class => [ + // FlushUploadedFiles::class, + ], + + TaskReceived::class => [ + ...Octane::prepareApplicationForNextOperation(), + // + ], + + TaskTerminated::class => [ + // + ], + + TickReceived::class => [ + ...Octane::prepareApplicationForNextOperation(), + // + ], + + TickTerminated::class => [ + // + ], + + OperationTerminated::class => [ + FlushOnce::class, + FlushTemporaryContainerInstances::class, + // DisconnectFromDatabases::class, + // CollectGarbage::class, + ], + + WorkerErrorOccurred::class => [ + ReportException::class, + StopWorkerIfNecessary::class, + ], + + WorkerStopping::class => [ + CloseMonologHandlers::class, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Warm / Flush Bindings + |-------------------------------------------------------------------------- + | + | The bindings listed below will either be pre-warmed when a worker boots + | or they will be flushed before every new request. Flushing a binding + | will force the container to resolve that binding again when asked. + | + */ + + 'warm' => [ + ...Octane::defaultServicesToWarm(), + ], + + 'flush' => [ + // + ], + + /* + |-------------------------------------------------------------------------- + | Octane Swoole Tables + |-------------------------------------------------------------------------- + | + | While using Swoole, you may define additional tables as required by the + | application. These tables can be used to store data that needs to be + | quickly accessed by other workers on the particular Swoole server. + | + */ + + 'tables' => [ + 'example:1000' => [ + 'name' => 'string:1000', + 'votes' => 'int', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Octane Swoole Cache Table + |-------------------------------------------------------------------------- + | + | While using Swoole, you may leverage the Octane cache, which is powered + | by a Swoole table. You may set the maximum number of rows as well as + | the number of bytes per row using the configuration options below. + | + */ + + 'cache' => [ + 'rows' => 1000, + 'bytes' => 10000, + ], + + /* + |-------------------------------------------------------------------------- + | File Watching + |-------------------------------------------------------------------------- + | + | The following list of files and directories will be watched when using + | the --watch option offered by Octane. If any of the directories and + | files are changed, Octane will automatically reload your workers. + | + */ + + 'watch' => [ + 'app', + 'bootstrap', + 'config/**/*.php', + 'database/**/*.php', + 'public/**/*.php', + 'resources/**/*.php', + 'routes', + 'composer.lock', + '.env', + ], + + /* + |-------------------------------------------------------------------------- + | Garbage Collection Threshold + |-------------------------------------------------------------------------- + | + | When executing long-lived PHP scripts such as Octane, memory can build + | up before being cleared by PHP. You can force Octane to run garbage + | collection if your application consumes this amount of megabytes. + | + */ + + 'garbage' => 50, + + /* + |-------------------------------------------------------------------------- + | Maximum Execution Time + |-------------------------------------------------------------------------- + | + | The following setting configures the maximum execution time for requests + | being handled by Octane. You may set this value to 0 to indicate that + | there isn't a specific time limit on Octane request execution time. + | + */ + + 'max_execution_time' => 30, + +]; diff --git a/database/migrations/2025_06_22_121731_create_user_permission_table.php b/database/migrations/2025_06_22_121731_create_user_permission_table.php deleted file mode 100644 index 4eba26b..0000000 --- a/database/migrations/2025_06_22_121731_create_user_permission_table.php +++ /dev/null @@ -1,31 +0,0 @@ -id(); - $table->foreignId('user_id')->constrained()->onDelete('cascade'); - $table->foreignId('permission_id')->constrained()->onDelete('cascade'); - $table->timestamps(); - - $table->unique(['user_id', 'permission_id']); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('user_permission'); - } -}; diff --git a/database/migrations/2025_06_22_141254_create_permission_user_table.php b/database/migrations/2025_06_22_141254_create_permission_user_table.php index 7515b98..81e3b8c 100644 --- a/database/migrations/2025_06_22_141254_create_permission_user_table.php +++ b/database/migrations/2025_06_22_141254_create_permission_user_table.php @@ -14,7 +14,7 @@ return new class extends Migration Schema::create('permission_user', function (Blueprint $table) { $table->id(); $table->foreignId('permission_id')->constrained()->cascadeOnDelete(); - $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignUuid('user_id')->constrained()->cascadeOnDelete(); $table->boolean('granted')->default(false); $table->timestamps(); }); diff --git a/package.json b/package.json index c49a064..b849a87 100644 --- a/package.json +++ b/package.json @@ -64,5 +64,5 @@ "@tailwindcss/oxide-linux-x64-gnu": "^4.1.8", "lightningcss-linux-x64-gnu": "^1.30.1" }, - "packageManager": "pnpm@10.12.3+sha512.467df2c586056165580ad6dfb54ceaad94c5a30f80893ebdec5a44c5aa73c205ae4a5bb9d5ed6bb84ea7c249ece786642bbb49d06a307df218d03da41c317417" + "packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184" } diff --git a/phpunit.xml b/phpunit.xml index 61c031c..c09b5bc 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -22,8 +22,7 @@ - - + diff --git a/resources/js/pages/tournaments/Show.svelte b/resources/js/pages/tournaments/Show.svelte index 7bbfb8d..5fa83b1 100644 --- a/resources/js/pages/tournaments/Show.svelte +++ b/resources/js/pages/tournaments/Show.svelte @@ -1,6 +1,7 @@ @@ -43,13 +70,17 @@ {/each} - - - - - + {#if addTeam} + + + + + {/if} + + + diff --git a/routes/api.php b/routes/api.php index f78b9c1..0a1747d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -3,6 +3,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use App\Http\Controllers\CompetitionController; +use App\Http\Controllers\TournamentController; Route::get('/user', function (Request $request) { return $request->user(); @@ -11,3 +12,5 @@ Route::get('/user', function (Request $request) { Route::get('/competitions/public', [CompetitionController::class, 'getPublicCompetitions']); Route::get('/competitions/user', [CompetitionController::class, 'getUserCompetitions'])->middleware('auth:api'); + +Route::post('/tournaments/{tournament}/addTeam', [TournamentController::class, 'addTeam'])->middleware(['auth', 'verified'])->name('tournaments.addTeam');