diff --git a/laravel/.env b/laravel/.env new file mode 100644 index 0000000..5266c50 --- /dev/null +++ b/laravel/.env @@ -0,0 +1,8 @@ +APP_NAME="Laravel Quiz App" +APP_ENV=local +APP_KEY=base64:MHMyGZ7hZG8z4V5j6F3qW1pL8n2R4s9X0yB7cE6dA= +APP_DEBUG=true +APP_URL=http://localhost:3000 + +DB_CONNECTION=sqlite +DB_DATABASE=/tmp/templates-fork/laravel/database.sqlite \ No newline at end of file diff --git a/laravel/README.md b/laravel/README.md new file mode 100644 index 0000000..4ce2f99 --- /dev/null +++ b/laravel/README.md @@ -0,0 +1,33 @@ +# Laravel Quiz App Template + +A basic quiz application built with Laravel for Codesphere workspaces. + +## Features + +- Create and manage quizzes +- Add multiple-choice questions to each quiz +- Take quizzes and see your score +- SQLite database (no external DB required) + +## Deployment on Codesphere + +1. Fork this template +2. In Codesphere, create a new workspace from your fork +3. Set up the CI pipeline (it will auto-run on Codesphere) +4. Click "Run" stage to start the dev server +5. Click "Open deployment" to access the app + +## Local Development + +```bash +composer install +touch database/database.sqlite +php artisan migrate +php artisan serve --host=0.0.0.0 --port=3000 +``` + +## Tech Stack + +- PHP 8.1+ +- Laravel 10 +- SQLite (file-based, no setup required) \ No newline at end of file diff --git a/laravel/app/Http/Controllers/Controller.php b/laravel/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..376e5b7 --- /dev/null +++ b/laravel/app/Http/Controllers/Controller.php @@ -0,0 +1,8 @@ +validate([ + 'quiz_id' => 'required|exists:quizzes,id', + 'question_text' => 'required|string', + 'options' => 'required|array|min:2', + 'correct_answer' => 'required|string', + ]); + + Question::create($validated); + return redirect()->route('quizzes.show', $validated['quiz_id'])->with('success', 'Question added!'); + } + + public function destroy(Question $question) + { + $quiz_id = $question->quiz_id; + $question->delete(); + return redirect()->route('quizzes.show', $quiz_id)->with('success', 'Question deleted!'); + } +} \ No newline at end of file diff --git a/laravel/app/Http/Controllers/QuizController.php b/laravel/app/Http/Controllers/QuizController.php new file mode 100644 index 0000000..3828f8d --- /dev/null +++ b/laravel/app/Http/Controllers/QuizController.php @@ -0,0 +1,55 @@ +latest()->paginate(10); + return view('quizzes.index', compact('quizzes')); + } + + public function create() + { + return view('quizzes.create'); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'description' => 'nullable|string', + ]); + + Quiz::create($validated); + return redirect()->route('quizzes.index')->with('success', 'Quiz created!'); + } + + public function show(Quiz $quiz) + { + $quiz->load('questions'); + return view('quizzes.show', compact('quiz')); + } + + public function take(Request $request, Quiz $quiz) + { + $answers = $request->except(['_token']); + $quiz->load('questions'); + + $score = 0; + $total = $quiz->questions->count(); + + foreach ($quiz->questions as $question) { + if (isset($answers['question_' . $question->id]) && + $answers['question_' . $question->id] === $question->correct_answer) { + $score++; + } + } + + return view('quizzes.result', compact('quiz', 'score', 'total')); + } +} \ No newline at end of file diff --git a/laravel/app/Models/Question.php b/laravel/app/Models/Question.php new file mode 100644 index 0000000..c70384c --- /dev/null +++ b/laravel/app/Models/Question.php @@ -0,0 +1,19 @@ + 'array', + ]; + + public function quiz() + { + return $this->belongsTo(Quiz::class); + } +} \ No newline at end of file diff --git a/laravel/app/Models/Quiz.php b/laravel/app/Models/Quiz.php new file mode 100644 index 0000000..f601273 --- /dev/null +++ b/laravel/app/Models/Quiz.php @@ -0,0 +1,15 @@ +hasMany(Question::class); + } +} \ No newline at end of file diff --git a/laravel/app/Providers/AppServiceProvider.php b/laravel/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..a4254c4 --- /dev/null +++ b/laravel/app/Providers/AppServiceProvider.php @@ -0,0 +1,18 @@ +make(Illuminate\Contracts\Console\Kernel::class); + +$status = $kernel->handle( + $input = new Symfony\Component\Console\Input\ArgvInput, + new Symfony\Component\Console\Output\ConsoleOutput +); + +$kernel->terminate($input, $status); + +exit($status); \ No newline at end of file diff --git a/laravel/bootstrap/app.php b/laravel/bootstrap/app.php new file mode 100644 index 0000000..3d8b5f7 --- /dev/null +++ b/laravel/bootstrap/app.php @@ -0,0 +1,18 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware) { + // + }) + ->withExceptions(function (Exceptions $exceptions) { + // + })->create(); \ No newline at end of file diff --git a/laravel/ci.yml b/laravel/ci.yml new file mode 100644 index 0000000..304ec06 --- /dev/null +++ b/laravel/ci.yml @@ -0,0 +1,14 @@ +prepare: + steps: + - name: "Install dependencies" + command: "composer install --no-interaction" + +test: + steps: + - name: "Run migrations" + command: "php artisan migrate --force 2>&1 || true" + +run: + steps: + - name: "Start Laravel dev server" + command: "php artisan serve --host=0.0.0.0 --port=3000" \ No newline at end of file diff --git a/laravel/composer.json b/laravel/composer.json new file mode 100644 index 0000000..7d520fa --- /dev/null +++ b/laravel/composer.json @@ -0,0 +1,51 @@ +{ + "name": "codesphere/laravel-quiz-app", + "description": "Laravel Quiz App Template for Codesphere", + "type": "project", + "require": { + "php": "^8.1", + "laravel/framework": "^10.0", + "guzzlehttp/guzzle": "^7.2" + }, + "require-dev": { + "fakerphp/faker": "^1.9.1", + "laravel/sail": "^1.18", + "mockery/mockery": "^1.4.4", + "nunomaduro/collision": "^7.0", + "phpunit/phpunit": "^10.1" + }, + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Factories\\": "database/factories/", + "Database\\Seeders\\": "database/seeders/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "scripts": { + "post-autoload-dump": [ + "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", + "@php artisan package:discover --ansi" + ] + }, + "extra": { + "laravel": { + "dont-discover": [] + } + }, + "config": { + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true, + "php-http/discovery": true + } + }, + "minimum-stability": "stable", + "prefer-stable": true +} \ No newline at end of file diff --git a/laravel/config/app.php b/laravel/config/app.php new file mode 100644 index 0000000..193f218 --- /dev/null +++ b/laravel/config/app.php @@ -0,0 +1,41 @@ + env('APP_NAME', 'Laravel Quiz App'), + 'env' => env('APP_ENV', 'production'), + 'debug' => (bool) env('APP_DEBUG', false), + 'url' => env('APP_URL', 'http://localhost'), + 'timezone' => 'UTC', + 'locale' => 'en', + 'fallback_locale' => 'en', + 'faker_locale' => 'en_US', + 'key' => env('APP_KEY'), + 'cipher' => 'AES-256-CBC', + 'maintenance' => ['driver' => 'file'], + 'providers' => [ + Illuminate\Auth\AuthServiceProvider::class, + Illuminate\Broadcasting\BroadcastServiceProvider::class, + Illuminate\Bus\BusServiceProvider::class, + Illuminate\Cache\CacheServiceProvider::class, + Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, + Illuminate\Cookie\CookieServiceProvider::class, + Illuminate\Database\DatabaseServiceProvider::class, + Illuminate\Encryption\EncryptionServiceProvider::class, + Illuminate\Filesystem\FilesystemServiceProvider::class, + Illuminate\Foundation\Providers\FoundationServiceProvider::class, + Illuminate\Hashing\HashServiceProvider::class, + Illuminate\Mail\MailServiceProvider::class, + Illuminate\Notifications\NotificationServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, + Illuminate\Pipeline\PipelineServiceProvider::class, + Illuminate\Queue\QueueServiceProvider::class, + Illuminate\Redis\RedisServiceProvider::class, + Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, + Illuminate\Session\SessionServiceProvider::class, + Illuminate\Translation\TranslationServiceProvider::class, + Illuminate\Validation\ValidationServiceProvider::class, + Illuminate\View\ViewServiceProvider::class, + App\Providers\AppServiceProvider::class, + ], + 'aliases' => Illuminate\Support\Facades\Facade::defaultAliases()->toArray(), +]; \ No newline at end of file diff --git a/laravel/config/database.php b/laravel/config/database.php new file mode 100644 index 0000000..7305081 --- /dev/null +++ b/laravel/config/database.php @@ -0,0 +1,18 @@ + 'sqlite', + 'connections' => [ + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DATABASE_URL'), + 'database' => database_path('database.sqlite'), + 'prefix' => '', + 'foreign_key_constraints' => true, + ], + ], + 'migrations' => [ + 'table' => 'migrations', + 'update_date_on_publish' => true, + ], +]; \ No newline at end of file diff --git a/laravel/database/migrations/2024_01_01_000000_create_quizzes_questions_tables.php b/laravel/database/migrations/2024_01_01_000000_create_quizzes_questions_tables.php new file mode 100644 index 0000000..73b9156 --- /dev/null +++ b/laravel/database/migrations/2024_01_01_000000_create_quizzes_questions_tables.php @@ -0,0 +1,33 @@ +id(); + $table->string('title'); + $table->text('description')->nullable(); + $table->timestamps(); + }); + + Schema::create('questions', function (Blueprint $table) { + $table->id(); + $table->foreignId('quiz_id')->constrained()->onDelete('cascade'); + $table->text('question_text'); + $table->json('options'); + $table->string('correct_answer'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('questions'); + Schema::dropIfExists('quizzes'); + } +}; \ No newline at end of file diff --git a/laravel/laravel.webp b/laravel/laravel.webp new file mode 100644 index 0000000..e69de29 diff --git a/laravel/metadata.json b/laravel/metadata.json new file mode 100644 index 0000000..278efa3 --- /dev/null +++ b/laravel/metadata.json @@ -0,0 +1,9 @@ +{ + "Workspace": "free", + "Links": { + "Laravel": "https://codesphere.com/articles/laravel" + }, + "Categories": ["Framework", "PHP"], + "Contributors": ["opencode-MiniMaxM27"], + "Title": "Laravel Quiz App" +} \ No newline at end of file diff --git a/laravel/public/index.php b/laravel/public/index.php new file mode 100644 index 0000000..6311fb8 --- /dev/null +++ b/laravel/public/index.php @@ -0,0 +1,11 @@ +handleRequest(Request::capture()); \ No newline at end of file diff --git a/laravel/resources/views/layouts/app.blade.php b/laravel/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..90c4576 --- /dev/null +++ b/laravel/resources/views/layouts/app.blade.php @@ -0,0 +1,50 @@ + + +
+ + +| Title | +Questions | +Actions | +
|---|---|---|
|
+ {{ $quiz->title }}
+ @if($quiz->description)
+ {{ $quiz->description }} + @endif + |
+ {{ $quiz->questions_count }} questions | ++ View + | +
+ No quizzes yet. Create the first one! +
+ @endif ++ @if($score >= $total * 0.7) + Great job! You passed! + @elseif($score >= $total * 0.4) + Not bad! Keep practicing. + @else + Keep learning and try again! + @endif +
+ +{{ $quiz->description }}
+ @endif + + @if($quiz->questions->count() > 0) + + @else ++ No questions yet. Add some questions to make the quiz playable. +
+ @endif +