1
0

Compare commits

...

6 Commits

27 changed files with 814 additions and 245 deletions

View File

@ -0,0 +1,93 @@
<?php
namespace App\Http\Controllers;
use App\Models\AssignedTests;
use App\Models\MultipleChoiceAnswers;
use App\Models\SingleChoiceAnswer;
use App\Models\SingleQuestionAnswers;
use App\Models\Test;
use App\Models\User;
use Illuminate\Http\Request;
class AssignedTestsController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validated = $request->validate([
"test_id" => "required|integer",
"student_id" => "required|integer"
]);
AssignedTests::create($validated);
return redirect(route("tests.edit", [
"test" => Test::where("id", $validated["test_id"])->first()
]));
}
/**
* Display the specified resource.
*/
public function show($assigned_student)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit($assigned_student)
{
$obj = AssignedTests::where("id", $assigned_student);
$obj->update([
"allowed" => "1"
]);
$test_id = $obj->first()->test_id;
return redirect(route("tests.edit", [
"test" => Test::where("id", $test_id)->first()
]));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, AssignedTests $assigned_student)
{
// $test->update($validated);
}
/**
* Remove the specified resource from storage.
*/
public function destroy($assigned_student)
{
$obj = AssignedTests::where("id", $assigned_student);
$test_id = $obj->first()->test_id;
$obj->delete();
return redirect(route("tests.edit", [
"test" => Test::where("id", $test_id)->first()
]));
}
}

View File

@ -8,6 +8,7 @@ use App\Models\SingleChoiceAnswer;
use App\Models\SingleQuestionAnswers;
use App\Models\Test;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class QuestionController extends Controller
{
@ -27,50 +28,89 @@ class QuestionController extends Controller
//
}
public function get_validation_rules($answer_type) {
$validation_rules = [
"question" => "required|string",
"points" => "required|integer|min:1",
"test_id" => "required|integer",
"answer_type" => "required|string",
];
if ($answer_type == "single_answer") {
$validation_rules["answer"] = "required|string";
} else if ($answer_type == "single_choice") {
$validation_rules["correct_answer"] = "required|string";
$validation_rules["incorrect_answer1"] = "required|string";
$validation_rules["incorrect_answer2"] = "nullable|string";
$validation_rules["incorrect_answer3"] = "nullable|string";
} else if ($answer_type == "multiple_choice") {
$validation_rules["answer1"] = "required|string";
$validation_rules["answer2"] = "required|string";
$validation_rules["answer3"] = "nullable|string";
$validation_rules["answer4"] = "nullable|string";
$validation_rules["is_answer1_correct"] = "nullable|string";
$validation_rules["is_answer2_correct"] = "nullable|string";
$validation_rules["is_answer3_correct"] = "nullable|string";
$validation_rules["is_answer4_correct"] = "nullable|string";
}
return $validation_rules;
}
public function get_answer_payload($question_id, $validated) {
if ($validated["answer_type"] == "single_answer") {
return [
"question_id" => $question_id,
"answer" => $validated["answer"],
];
} else if ($validated["answer_type"] == "single_choice") {
return [
"question_id" => $question_id,
"correct_answer" => $validated["correct_answer"],
"incorrect_answer1" => $validated["incorrect_answer1"],
"incorrect_answer2" => $validated["incorrect_answer2"],
"incorrect_answer3" => $validated["incorrect_answer3"],
];
} else if ($validated["answer_type"] == "multiple_choice") {
$validated["is_answer1_correct"] = !empty($validated["is_answer1_correct"]) && $validated["is_answer1_correct"] == "on";
$validated["is_answer2_correct"] = !empty($validated["is_answer2_correct"]) && $validated["is_answer2_correct"] == "on";
$validated["is_answer3_correct"] = !empty($validated["is_answer3_correct"]) && $validated["is_answer3_correct"] == "on";
$validated["is_answer4_correct"] = !empty($validated["is_answer4_correct"]) && $validated["is_answer4_correct"] == "on";
return [
"question_id" => $question_id,
"answer1" => $validated["answer1"],
"answer2" => $validated["answer2"],
"answer3" => $validated["answer3"],
"answer4" => $validated["answer4"],
"is_answer1_correct" => $validated["is_answer1_correct"],
"is_answer2_correct" => $validated["is_answer2_correct"],
"is_answer3_correct" => $validated["is_answer3_correct"],
"is_answer4_correct" => $validated["is_answer4_correct"],
];
}
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validated = $request->validate([
"question" => "required|string",
"points" => "required|integer|min:1",
"test_id" => "required|integer",
"answer_type" => "required|string",
$validation_rules = $this->get_validation_rules($request->answer_type);
$validated = $request->validate($validation_rules);
$question = Question::create([
"question" => $validated["question"],
"points" => $validated["points"],
"test_id" => $validated["test_id"],
"answer_type" => $validated["answer_type"],
]);
if ($request->answer_type == "single_answer") {
$validated_answer = $request->validate([
"answer" => "required|string",
]);
SingleQuestionAnswers::create($this->get_answer_payload($question->id, $validated));
} else if ($request->answer_type == "single_choice") {
$validated_answer = $request->validate([
"correct_answer" => "required|string",
"incorrect_answer1" => "required|string",
"incorrect_answer2" => "nullable|string",
"incorrect_answer3" => "nullable|string",
]);
SingleChoiceAnswer::create($this->get_answer_payload($question->id, $validated));
} else if ($request->answer_type == "multiple_choice") {
$validated_answer = $request->validate([
"answer1" => "required|string",
"answer2" => "required|string",
"answer3" => "nullable|string",
"answer4" => "nullable|string",
"is_answer1_correct" => "nullable|boolean",
"is_answer2_correct" => "nullable|boolean",
"is_answer3_correct" => "nullable|boolean",
"is_answer4_correct" => "nullable|boolean",
]);
}
$question = Question::create($validated);
$validated_answer["question_id"] = $question->id;
if ($request->answer_type == "single_answer") {
SingleQuestionAnswers::create($validated_answer);
} else if ($request->answer_type == "single_choice") {
SingleChoiceAnswer::create($validated_answer);
} else if ($request->answer_type == "multiple_choice") {
MultipleChoiceAnswers::create($validated_answer);
MultipleChoiceAnswers::create($this->get_answer_payload($question->id, $validated));
}
return redirect(route("tests.edit", [
@ -129,11 +169,48 @@ class QuestionController extends Controller
"points" => "required|integer|min:1"
]);
$question->update($validated);
$validation_rules = $this->get_validation_rules($request->answer_type);
$validated = $request->validate($validation_rules);
return view("tests.edit", [
"test" => $validated["test_id"]
$prev_answer_type = $question->answer_type;
$question->update([
"question" => $validated["question"],
"points" => $validated["points"],
"test_id" => $validated["test_id"],
"answer_type" => $validated["answer_type"],
]);
if ($prev_answer_type != $validated["answer_type"]) {
if ($prev_answer_type == "single_answer") {
SingleQuestionAnswers::where("question_id", $question->id)->delete();
} else if ($prev_answer_type == "single_choice") {
SingleChoiceAnswer::where("question_id", $question->id)->delete();
} else if ($prev_answer_type == "multiple_choice") {
MultipleChoiceAnswers::where("question_id", $question->id)->delete();
}
if ($request->answer_type == "single_answer") {
SingleQuestionAnswers::create($this->get_answer_payload($question->id, $validated));
} else if ($request->answer_type == "single_choice") {
SingleChoiceAnswer::create($this->get_answer_payload($question->id, $validated));
} else if ($request->answer_type == "multiple_choice") {
MultipleChoiceAnswers::create($this->get_answer_payload($question->id, $validated));
}
} else {
if ($request->answer_type == "single_answer") {
SingleQuestionAnswers::where("question_id", $question->id)
->update($this->get_answer_payload($question->id, $validated));
} else if ($request->answer_type == "single_choice") {
SingleChoiceAnswer::where("question_id", $question->id)
->update($this->get_answer_payload($question->id, $validated));
} else if ($request->answer_type == "multiple_choice") {
MultipleChoiceAnswers::where("question_id", $question->id)
->update($this->get_answer_payload($question->id, $validated));
}
}
$test = Test::where("id", $request->test_id)->first();
return redirect(route("tests.edit", $test));
}
/**

View File

@ -2,10 +2,13 @@
namespace App\Http\Controllers;
use App\Models\AssignedTests;
use App\Models\MultipleChoiceAnswers;
use App\Models\SingleChoiceAnswer;
use App\Models\SingleQuestionAnswers;
use App\Models\Test;
use App\Models\TestResult;
use App\Models\User;
use Illuminate\Http\Request;
class TestController extends Controller
@ -83,9 +86,35 @@ class TestController extends Controller
}
}
$students = User::where("role", "student")->get()->toArray();
$assigned_students = [];
foreach (AssignedTests::where("test_id", $test->id)->get() as $assigned_student) {
$backing_student = User::where("id", $assigned_student->student_id)->first();
$assigned_student->name = $backing_student->name;
foreach ($students as $idx => $student) {
if ($student["id"] == $assigned_student->student_id) {
unset($students[$idx]);
}
}
array_push($assigned_students, $assigned_student);
}
$test_results = [];
foreach (TestResult::where("test_id", $test->id)->get() as $test_result) {
$student = User::where("id", $test_result->student_id)->first();
$test_result->student_name = $student->name;
array_push($test_results, $test_result);
}
return view("tests.edit", [
"test" => $test,
"questions" => $questions,
"students" => $students,
"assigned_students" => $assigned_students,
"test_results" => $test_results
]);
}

View File

@ -2,7 +2,14 @@
namespace App\Http\Controllers;
use App\Models\AssignedTests;
use App\Models\MultipleChoiceAnswers;
use App\Models\Question;
use App\Models\SingleChoiceAnswer;
use App\Models\SingleQuestionAnswers;
use App\Models\Test;
use App\Models\TestQuestionResult;
use App\Models\TestResult;
use Illuminate\Http\Request;
class TestTakingController extends Controller
@ -12,7 +19,18 @@ class TestTakingController extends Controller
*/
public function index(Request $request)
{
return view("test-taking");
$user = $request->user();
$assigned_tests = [];
foreach (AssignedTests::where("student_id", $user->id)->get() as $assigned_test) {
if ($assigned_test->allowed) {
array_push($assigned_tests, Test::where("id", $assigned_test->test_id)->first());
}
}
return view("take_tests.index", [
"assigned_tests" => $assigned_tests
]);
}
/**
@ -28,7 +46,78 @@ class TestTakingController extends Controller
*/
public function store(Request $request)
{
//
$test_id = $request->test_id;
$answers = $request->answer;
$questions = Question::where("test_id", $test_id)->get();
$total_points = 0;
$max_points = 0;
$question_results = [];
foreach ($questions as $idx => $question) {
$points = 0;
$student_answer = "";
if (!empty($answers[$idx])) {
$student_answer = $answers[$idx];
if ($question->answer_type == "single_answer") {
$answer = SingleQuestionAnswers::where("question_id", $question->id)->first();
if ($student_answer == $answer->answer) {
$points = $question->points;
}
} else if ($question->answer_type == "single_choice") {
$answer = SingleChoiceAnswer::where("question_id", $question->id)->first();
if ($student_answer == $answer->correct_answer) {
$points = $question->points;
}
} else if ($question["answer_type"] == "multiple_choice") {
$answer = MultipleChoiceAnswers::where("question_id", $question->id)->first();
$correct_answers = [];
if ($answer->is_answer1_correct) {
array_push($correct_answers, $answer->answer1);
}
if ($answer->is_answer2_correct) {
array_push($correct_answers, $answer->answer2);
}
if ($answer->is_answer3_correct) {
array_push($correct_answers, $answer->answer3);
}
if ($answer->is_answer4_correct) {
array_push($correct_answers, $answer->answer4);
}
$points = count(array_intersect($correct_answers, $student_answer)) / count($correct_answers);
$student_answer = join(", ", $student_answer);
}
}
$max_points += $question->points;
$total_points += $points;
array_push($question_results, [
"question_id" => $question->id,
"points" => $points,
"answer" => $student_answer
]);
}
$user = $request->user();
$test_result = TestResult::create([
"student_id" => $user->id,
"test_id" => $test_id,
"points" => $total_points,
"max_points" => $max_points
]);
foreach ($question_results as $question_result) {
$question_result["test_results_id"] = $test_result->id;
TestQuestionResult::create($question_result);
}
AssignedTests::where("test_id", $test_id)
->where("student_id", $user->id)
->update([ "allowed" => false ]);
return view('dashboard');
}
/**
@ -42,9 +131,44 @@ class TestTakingController extends Controller
/**
* Show the form for editing the specified resource.
*/
public function edit(Test $test)
public function edit($test_id)
{
//
$question_answers = [];
$questions = Question::where("test_id", $test_id)->get();
foreach ($questions as $question) {
$question_answer = $question->toArray();
if ($question->answer_type == "single_answer") {
$answer = SingleQuestionAnswers::where("question_id", $question->id)->first();
$question_answer["answer"] = $answer->answer;
} else if ($question->answer_type == "single_choice") {
$answer = SingleChoiceAnswer::where("question_id", $question->id)->first();
$question_answer["answers"] = [$answer->correct_answer, $answer->incorrect_answer1];
if ($answer->incorrect_answer2) {
array_push($question_answer["answers"], $answer->incorrect_answer2);
}
if ($answer->incorrect_answer3) {
array_push($question_answer["answers"], $answer->incorrect_answer3);
}
shuffle($question_answer["answers"]);
} else if ($question["answer_type"] == "multiple_choice") {
$answer = MultipleChoiceAnswers::where("question_id", $question->id)->first();
$question_answer["answers"] = [$answer->answer1, $answer->answer2];
if ($answer->answer3) {
array_push($question_answer["answers"], $answer->answer3);
}
if ($answer->answer4) {
array_push($question_answer["answers"], $answer->answer4);
}
shuffle($question_answer["answers"]);
}
array_push($question_answers, $question_answer);
}
return view("take_tests.edit", [
"test_id" => $test_id,
"questions" => $question_answers
]);
}
/**

View File

@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class AssignedTests extends Model
{
use HasFactory;
protected $fillable = [
"test_id",
'student_id',
];
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TestQuestionResult extends Model
{
use HasFactory;
protected $fillable = [
"test_results_id",
"question_id",
"points",
"answer"
];
}

18
app/Models/TestResult.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TestResult extends Model
{
use HasFactory;
protected $fillable = [
"student_id",
"test_id",
"points",
"max_points"
];
}

View File

@ -91,12 +91,6 @@ return [
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_reset_tokens',
'expire' => 60,
'throttle' => 60,
],
],
/*

View File

@ -101,9 +101,6 @@ return [
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],
];

View File

@ -1,28 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('password_reset_tokens', function (Blueprint $table) {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('password_reset_tokens');
}
};

View File

@ -1,32 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->string('uuid')->unique();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('failed_jobs');
}
};

View File

@ -1,33 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('personal_access_tokens');
}
};

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('test_results', function (Blueprint $table) {
$table->id();
$table->foreignId("student_id")->references("id")->on("users")->constrained()->cascadeOnDelete();
$table->foreignId("test_id")->references("id")->on("tests")->constrained()->cascadeOnDelete();
$table->float("points")->default(0);
$table->float("max_points")->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('test_results');
}
};

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('test_question_results', function (Blueprint $table) {
$table->id();
$table->foreignId("test_results_id")->references("id")->on("test_results")->constrained()->cascadeOnDelete();
$table->foreignId("question_id")->references("id")->on("questions")->constrained()->cascadeOnDelete();
$table->float("points")->default(0);
$table->string("answer");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('test_question_results');
}
};

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('assigned_tests', function (Blueprint $table) {
$table->id();
$table->foreignId("student_id")->references("id")->on("users")->constrained()->cascadeOnDelete();
$table->foreignId("test_id")->references("id")->on("tests")->constrained()->cascadeOnDelete();
$table->boolean("allowed")->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('assigned_tests');
}
};

View File

@ -4,11 +4,14 @@ namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use App\Models\AssignedTests;
use App\Models\MultipleChoiceAnswers;
use App\Models\Question;
use App\Models\SingleChoiceAnswer;
use App\Models\SingleQuestionAnswers;
use App\Models\Test;
use App\Models\TestQuestionResult;
use App\Models\TestResult;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
@ -32,7 +35,7 @@ class DatabaseSeeder extends Seeder
'password' => Hash::make("bob"),
'role' => "teacher"
]);
User::create([
$alice = User::create([
'name' => "Alice student",
'email' => "alice@student",
'password' => Hash::make("alice"),
@ -44,43 +47,71 @@ class DatabaseSeeder extends Seeder
"user_id" => $teacher->id
]);
$question_1 = Question::create([
"test_id" => $test->id,
"question" => "1+1=?",
"answer_type" => "single_answer",
]);
SingleQuestionAnswers::create([
"question_id" => $question_1->id,
"answer" => "2"
]);
$question_2 = Question::create([
"test_id" => $test->id,
"question" => "Gyvenimo prasme",
"answer_type" => "single_choice",
]);
SingleChoiceAnswer::create([
"question_id" => $question_2->id,
"correct_answer" => "42",
"incorrect_answer1" => "Kates",
"incorrect_answer3" => "Sunys",
]);
$question_3 = Question::create([
"test_id" => $test->id,
"question" => "Siandienos orai",
"answer_type" => "multiple_choice",
]);
MultipleChoiceAnswers::create([
"question_id" => $question_3->id,
"answer1" => "Sninga", "is_answer1_correct" => true,
"answer2" => "Lija", "is_answer2_correct" => true,
"answer4" => "Idk, paziurek per langa", "is_answer4_correct" => false,
]);
{
$question = Question::create([
AssignedTests::create([
"student_id" => $alice->id,
"test_id" => $test->id,
"question" => "1+1=?",
"answer_type" => "single_answer",
"allowed" => false
]);
SingleQuestionAnswers::create([
"question_id" => $question->id,
$test_result = TestResult::create([
"student_id" => $alice->id,
"test_id" => $test->id,
"points" => 2.5,
"max_points" => 3
]);
TestQuestionResult::create([
"test_results_id" => $test_result->id,
"question_id" => $question_1->id,
"points" => 1,
"answer" => "2"
]);
}
{
$question = Question::create([
"test_id" => $test->id,
"question" => "Gyvenimo prasme",
"answer_type" => "single_choice",
TestQuestionResult::create([
"test_results_id" => $test_result->id,
"question_id" => $question_2->id,
"points" => 1,
"answer" => "42"
]);
SingleChoiceAnswer::create([
"question_id" => $question->id,
"correct_answer" => "42",
"incorrect_answer1" => "Kates",
"incorrect_answer3" => "Sunys",
]);
}
{
$question = Question::create([
"test_id" => $test->id,
"question" => "Siandienos orai",
"answer_type" => "multiple_choice",
]);
MultipleChoiceAnswers::create([
"question_id" => $question->id,
"answer1" => "Sninga", "is_answer1_correct" => true,
"answer2" => "Lija", "is_answer2_correct" => true,
"answer4" => "Idk, paziurek per langa", "is_answer4_correct" => false,
TestQuestionResult::create([
"test_results_id" => $test_result->id,
"question_id" => $question_3->id,
"points" => 0.5,
"answer" => "Lija"
]);
}

View File

@ -26,5 +26,29 @@
"Question": "Klausimas",
"Answer": "Atsakymas",
"Points": "Taškai",
"Add question": "Pridėti klausimą"
"Add question": "Pridėti klausimą",
"Grade": "Pažymys",
"Can take test": "Gali laikyti testą",
"Allow to take test": "Leisti laikyti testą",
"Add student": "Pridėti studentą",
"Test results": "Testų rezultatai",
"Assigned students": "Priskirti studentai",
"Questions": "Klausimai",
"Single": "Vienas",
"Single choice": "Pasirinkti vieną",
"Multiple choice": "Pasirinkti kelis",
"Answer type": "Atsakymo tipas",
"Correct answer": "Teisingas atsakymas",
"Answer 1": "Atsakymas 1",
"Answer 2": "Atsakymas 2",
"Answer 3": "Atsakymas 3",
"Answer 4": "Atsakymas 4",
"Incorrect answer 1": "Neteisingas atsakymas 1",
"Incorrect Answer 2": "Neteisingas atsakymas 2",
"Incorrect answer 3": "Neteisingas atsakymas 3",
"Do test:": "Atlikti testą:",
"Question:": "Klausimas",
"Answer:": "Atsakymas",
"End test": "Pabaigti testą",
"-- Empty --": "-- Tuščia --"
}

View File

@ -69,7 +69,7 @@ return [
'image' => 'The :attribute field must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field must exist in :other.',
'integer' => 'The :attribute field must be an integer.',
'integer' => 'Laukas \':attribute\' turi būti sveikasis skaičius',
'ip' => 'The :attribute field must be a valid IP address.',
'ipv4' => 'The :attribute field must be a valid IPv4 address.',
'ipv6' => 'The :attribute field must be a valid IPv6 address.',
@ -100,7 +100,7 @@ return [
'min' => [
'array' => 'The :attribute field must have at least :min items.',
'file' => 'The :attribute field must be at least :min kilobytes.',
'numeric' => 'The :attribute field must be at least :min.',
'numeric' => 'Laukas \':attribute\' turi būti nors :min.',
'string' => 'The :attribute field must be at least :min characters.',
],
'min_digits' => 'The :attribute field must have at least :min digits.',
@ -126,7 +126,7 @@ return [
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'prohibits' => 'The :attribute field prohibits :other from being present.',
'regex' => 'The :attribute field format is invalid.',
'required' => 'Laukas \':attribute\' field yra butinas.',
'required' => 'Laukas \':attribute\' yra būtinas.',
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_if_accepted' => 'The :attribute field is required when :other is accepted.',
@ -180,6 +180,14 @@ return [
|
*/
'attributes' => [],
'attributes' => [
"question" => "klausimas",
"answer" => "atsakymas",
"answer1" => "atsakymas 1",
"answer2" => "atsakymas 2",
"correct_answer" => "teisingas atsakymas",
"incorrect_answer1" => "neteisingas atsakymas 1",
"points" => "taškai"
],
];

View File

@ -52,7 +52,7 @@
@for ($idx = 1; $idx <= 3; $idx++)
<x-input-label>{{ __("Incorrect answer ".$idx) }}</x-input-label>
<x-text-input class="w-full" name="incorrect_answer{{$idx}}" placeholder="{{ __('Incorrect answer '.$idx) }}" value="{{ old('incorrect_answer'.$idx, ${'default_incorrect_answer'.$idx}) }}" />
<x-input-error :messages="$errors->get('incorrect_answer{{$idx}}')" class="mt-2" />
<x-input-error :messages="$errors->get('incorrect_answer'.$idx)" class="mt-2" />
@endfor
</div>
@ -61,7 +61,7 @@
<div>
<x-input-label>{{ __("Answer ".$idx) }}</x-input-label>
<x-text-input class="w-full" name="answer{{ $idx }}" placeholder="{{ __('Answer '.$idx) }}" value="{{ old('answer'.$idx, ${'default_answer'.$idx}) }}" />
<x-input-error :messages="$errors->get('answer{{ $idx }}')" class="mt-2" />
<x-input-error :messages="$errors->get('answer'.$idx)" class="mt-2" />
<x-bool-input name="is_answer{{$idx}}_correct" checked="{{ old('is_answer'.$idx.'_correct', ${'default_is_answer'.$idx.'_correct'}) }}" />
</div>
@ -87,5 +87,5 @@
$("#answer_type").on("change", function() {
show(this.value)
})
show("{{ $default_answer_type }}")
show("{{ old('answer_type', $default_answer_type) }}")
</script>

View File

@ -26,7 +26,7 @@
</x-nav-link>
@endif
@if (Auth::user()->role == "student")
<x-nav-link :href="route('take-tests')" :active="request()->routeIs('take-tests')">
<x-nav-link :href="route('take_tests.index')" :active="request()->routeIs('take_tests.index')">
{{ __('Take tests') }}
</x-nav-link>
@endif
@ -96,7 +96,7 @@
</x-responsive-nav-link>
@endif
@if (Auth::user()->role == "student")
<x-responsive-nav-link :href="route('take-tests')" :active="request()->routeIs('take-tests')">
<x-responsive-nav-link :href="route('take_tests.index')" :active="request()->routeIs('take_tests.index')">
{{ __('Take tests') }}
</x-responsive-nav-link>
@endif

View File

@ -4,7 +4,6 @@
@csrf
@method("patch")
<div class="flex flex-col gap-1">
{{ $question->answer_type }}
<x-question-fields
:test_id="$question->test_id"
:default_question="$question->question"

View File

@ -1,4 +0,0 @@
<x-app-layout>
<div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8">
</div>
</x-app-layout>

View File

@ -0,0 +1,36 @@
<x-app-layout>
<div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8">
<form method="POST" action="{{ route('take_tests.store') }}">
@csrf
<input type="hidden" value="{{ $test_id }}" name="test_id">
<div class="flex flex-col gap-5 mb-10">
@foreach ($questions as $idx => $question)
<div class="rounded overflow-hidden shadow-lg bg-slate-200 p-5">
<div class="mb-2">
{{ __("Question:") }}
{{ $question["question"] }}
</div>
{{ __("Answer:") }}
@if ($question["answer_type"] == "single_answer")
<x-text-input name="answer[]" placeholder="{{ __('Answer') }}" />
@elseif ($question["answer_type"] == "single_choice")
<x-select name="answer[]">
@foreach ($question["answers"] as $answer)
<option value="{{ $answer }}">{{ $answer }}</option>
@endforeach
</x-select>
@elseif ($question["answer_type"] == "multiple_choice")
@foreach ($question["answers"] as $answer)
<div>
<x-bool-input name="answer[{{$idx}}][]" value="{{$answer}}" />
{{ $answer }}
</div>
@endforeach
@endif
</div>
@endforeach
</div>
<x-primary-button>{{ __("End test") }}</x-primary-button>
</form>
</div>
</x-app-layout>

View File

@ -0,0 +1,11 @@
<x-app-layout>
<div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8">
<div class="flex flex-col">
@foreach ($assigned_tests as $test)
<form method="GET" action="{{ route("take_tests.edit", $test) }}">
<x-primary-button>{{ __("Do test:") }} {{ $test->name }}</x-primary-button>
</form>
@endforeach
<div>
</div>
</x-app-layout>

View File

@ -16,58 +16,148 @@
</form>
<hr class="mt-6 mb-6">
<div>
<h2 class="text-center text-lg font-medium">{{ __("Questions") }}</h2>
<form method="POST" action="{{ route('questions.store') }}">
@csrf
<div class="flex flex-col gap-1">
<x-question-fields
:test_id="$test->id"
/>
</div>
<form method="POST" action="{{ route('questions.store') }}">
@csrf
<div class="flex flex-col gap-1">
<x-question-fields
:test_id="$test->id"
/>
</div>
<div class="mt-4 space-x-2">
<x-primary-button>{{ __("Add question") }}</x-primary-button>
</div>
</form>
<div class="mt-4 space-x-2">
<x-primary-button>{{ __("Add question") }}</x-primary-button>
</div>
</form>
<table class="mt-6 border border-gray-300 w-full text-left">
<tr>
<th class="border border-gray-300 p-1">{{ __("Question") }}</th>
<th class="border border-gray-300 p-1">{{ __("Answer") }}</th>
<th class="border border-gray-300 p-1">{{ __("Points") }}</th>
<th class="border border-gray-300 p-1"></th>
</tr>
<table class="mt-6 border border-gray-300 w-full text-left">
<tr>
<th class="border border-gray-300 p-1">{{ __("Question") }}</th>
<th class="border border-gray-300 p-1">{{ __("Answer") }}</th>
<th class="border border-gray-300 p-1">{{ __("Points") }}</th>
<th class="border border-gray-300 p-1"></th>
</tr>
@foreach ($questions as $question)
<tr>
<td class="border border-gray-300 p-1">{{ $question->question }}</td>
<td class="border border-gray-300 p-1">{{ $question->answer }}</td>
<td class="border border-gray-300 p-1">{{ $question->points }}</td>
<td class="border border-gray-300 p-1">
<x-dropdown>
<x-slot name="trigger">
<button>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
<path d="M6 10a2 2 0 11-4 0 2 2 0 014 0zM12 10a2 2 0 11-4 0 2 2 0 014 0zM16 12a2 2 0 100-4 2 2 0 000 4z" />
</svg>
</button>
</x-slot>
<x-slot name="content">
<x-dropdown-link :href="route('questions.edit', $question)">
{{ __("Edit") }}
</x-dropdown-link>
<form method="POST" action="{{ route("questions.destroy", $question) }}">
@csrf
@method("delete")
<x-dropdown-link :href="route('questions.destroy', $question)" onclick="event.preventDefault(); this.closest('form').submit();">
{{ __("Delete") }}
@foreach ($questions as $question)
<tr>
<td class="border border-gray-300 p-1">{{ $question->question }}</td>
<td class="border border-gray-300 p-1">{{ $question->answer }}</td>
<td class="border border-gray-300 p-1">{{ $question->points }}</td>
<td class="border border-gray-300 p-1">
<x-dropdown>
<x-slot name="trigger">
<button>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
<path d="M6 10a2 2 0 11-4 0 2 2 0 014 0zM12 10a2 2 0 11-4 0 2 2 0 014 0zM16 12a2 2 0 100-4 2 2 0 000 4z" />
</svg>
</button>
</x-slot>
<x-slot name="content">
<x-dropdown-link :href="route('questions.edit', $question)">
{{ __("Edit") }}
</x-dropdown-link>
</form>
</x-slot>
</x-dropdown>
</td>
</tr>
@endforeach
</table>
<form method="POST" action="{{ route("questions.destroy", $question) }}">
@csrf
@method("delete")
<x-dropdown-link :href="route('questions.destroy', $question)" onclick="event.preventDefault(); this.closest('form').submit();">
{{ __("Delete") }}
</x-dropdown-link>
</form>
</x-slot>
</x-dropdown>
</td>
</tr>
@endforeach
</table>
</div>
<hr class="mt-6 mb-6">
<div>
<h2 class="text-center text-lg font-medium">{{ __("Assigned students") }}</h2>
<form method="POST" action="{{ route('assigned_tests.store') }}">
@csrf
<div class="flex flex-col gap-1">
<input type="hidden" value="{{ $test->id }}" name="test_id">
<x-input-label>{{ __("Student") }}</x-input-label>
<x-select name="student_id" id="student_id">
@if (sizeof($students) == 0)
<option selected disabled hidden>{{ __("-- Empty --") }}</option>
@endif
@foreach ($students as $student)
<option value="{{$student['id']}}" {{ old("student") == $student['id'] ? "selected" : "" }} >{{ $student['name'] }}</option>
@endforeach
</x-select>
</div>
<div class="mt-4 space-x-2">
<x-primary-button :disabled="sizeof($students) == 0">{{ __("Add student") }}</x-primary-button>
</div>
</form>
<table class="mt-6 border border-gray-300 w-full text-left">
<tr>
<th class="border border-gray-300 p-1">{{ __("Student") }}</th>
<th class="border border-gray-300 p-1">{{ __("Can take test") }}</th>
<th class="border border-gray-300 p-1"></th>
</tr>
@foreach ($assigned_students as $student)
<tr>
<td class="border border-gray-300 p-1">{{ $student->name }}</td>
<td class="border border-gray-300 p-1">{{ __($student->allowed ? "Yes" : "No") }}</td>
<td class="border border-gray-300 p-1">
<x-dropdown>
<x-slot name="trigger">
<button>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-400" viewBox="0 0 20 20" fill="currentColor">
<path d="M6 10a2 2 0 11-4 0 2 2 0 014 0zM12 10a2 2 0 11-4 0 2 2 0 014 0zM16 12a2 2 0 100-4 2 2 0 000 4z" />
</svg>
</button>
</x-slot>
<x-slot name="content">
@if (!$student->allowed)
<x-dropdown-link :href="route('assigned_tests.edit', $student)">
{{ __("Allow to take test") }}
</x-dropdown-link>
@endif
<form method="POST" action="{{ route("assigned_tests.destroy", $student) }}">
@csrf
@method("delete")
<x-dropdown-link :href="route('assigned_tests.destroy', $student)" onclick="event.preventDefault(); this.closest('form').submit();">
{{ __("Delete") }}
</x-dropdown-link>
</form>
</x-slot>
</x-dropdown>
</td>
</tr>
@endforeach
</table>
</div>
<hr class="mt-6 mb-6">
<div>
<h2 class="text-center text-lg font-medium">{{ __("Test results") }}</h2>
<table class="mt-6 border border-gray-300 w-full text-left">
<tr>
<th class="border border-gray-300 p-1">{{ __("Student") }}</th>
<th class="border border-gray-300 p-1">{{ __("Points") }}</th>
<th class="border border-gray-300 p-1">{{ __("Grade") }}</th>
</tr>
@foreach ($test_results as $test_result)
<tr>
<td class="border border-gray-300 p-1">{{ $test_result->student_name }}</td>
<td class="border border-gray-300 p-1">{{ $test_result->points }}</td>
<td class="border border-gray-300 p-1">{{ round($test_result->points / $test_result->max_points * 10, 2) }}</td>
</tr>
@endforeach
</table>
</div>
</div>
</x-app-layout>

View File

@ -20,9 +20,9 @@
@if (Route::has('login'))
<div class="sm:fixed sm:top-0 sm:right-0 p-6 text-right z-10">
@auth
<a href="{{ url('/dashboard') }}" class="font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">Dashboard</a>
<a href="{{ url('/dashboard') }}" class="font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">{{ __("Dashboard") }}</a>
@else
<a href="{{ route('login') }}" class="font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">Log in</a>
<a href="{{ route('login') }}" class="font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">{{ __("Log in") }}</a>
@endauth
</div>
@endif

View File

@ -1,9 +1,10 @@
<?php
use App\Http\Controllers\AssignedTestsController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\QuestionController;
use App\Http\Controllers\TestController;
use App\Http\Controllers\UserController;
use App\Http\Controllers\TestTakingController;
use Illuminate\Support\Facades\Route;
/*
@ -43,9 +44,17 @@ Route::resource("questions", QuestionController::class)
->only(["index", "store", "edit", "update", "destroy"])
->middleware(["auth", "verified"]);
Route::get('/take-tests', function () {
return view('take-tests');
})->middleware(['auth', 'verified'])->name('take-tests');
Route::resource("assigned_tests", AssignedTestsController::class)
->only(["index", "store", "edit", "update", "destroy"])
->middleware(["auth", "verified"]);
Route::resource("take_tests", TestTakingController::class)
->only(["index", "store", "edit", "update", "destroy"])
->middleware(["auth", "verified"]);
// Route::get('/take-tests', function () {
// return view('take-tests');
// })->middleware(['auth', 'verified'])->name('take-tests');
// Route::resource("test-taking", TestTakingController::class)
// ->only(["index"])