Compare commits

..

No commits in common. 'master' and 'feature/api-get-list-exercise' have entirely different histories.

  1. 42
      app/Auth/PassportUserRepository.php
  2. 19
      app/Http/Controllers/Api/ExerciseController.php
  3. 24
      app/Http/Resources/BlankResource.php
  4. 24
      app/Http/Resources/ChoiceResource.php
  5. 27
      app/Http/Resources/ExerciseResource.php
  6. 23
      app/Http/Resources/QuestionGroupResource.php
  7. 25
      app/Http/Resources/QuestionResource.php
  8. 22
      app/Http/Resources/SkillResource.php
  9. 12
      app/Models/Exercise.php
  10. 4
      app/Models/QuestionBlank.php
  11. 2
      app/Models/User.php
  12. 19
      app/Services/ExerciseService.php
  13. 8
      app/Services/QuestionService.php
  14. 3
      routes/api.php

@ -3,22 +3,13 @@
namespace App\Auth;
use Laravel\Passport\Bridge\UserRepository;
use Laravel\Passport\Bridge\UserRepositoryInterface;
use Laravel\Passport\Bridge\User;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use Laravel\Passport\Bridge\User;
use Illuminate\Support\Facades\Hash;
use App\Models\User as UserModel;
class PassportUserRepository extends UserRepository
{
/**
* OAuth2.
*
* @param string $username
* @param string $password
* @param string $grantType
* @param ClientEntityInterface $clientEntity
* @return User|null
*/
public function getUserEntityByUserCredentials(
$username,
$password,
@ -27,14 +18,37 @@ class PassportUserRepository extends UserRepository
) {
$user = UserModel::where('email', $username)->first();
if (! $user) {
if (!$user) {
return null;
}
if (md5($password) === $user->password) {
return new User($user->getAuthIdentifier());
// Avoid Hash::check() error with non-bcrypt hashes
if ($this->isBcryptHash($user->password)) {
if (Hash::check($password, $user->password)) {
return new User($user->id);
}
} else {
// If the hash is not bcrypt, check for MD5 manually
if (md5($password) === $user->password) {
// Upgrade password to bcrypt
$user->password = Hash::make($password);
$user->save();
return new User($user->id);
}
}
return null;
}
/**
* Check if the given hash uses the bcrypt algorithm.
*
* @param string $hashedPassword
* @return bool
*/
protected function isBcryptHash($hashedPassword): bool
{
return password_get_info($hashedPassword)['algo'] === PASSWORD_BCRYPT;
}
}

@ -75,23 +75,4 @@ class ExerciseController extends Controller
], 500);
}
}
public function detail($id)
{
$exercise = $this->exerciseService->detail($id);
if (empty($exercise)) {
return response()->json([
'status' => true,
'data' => $exercise,
'message' => 'Không có dữ liệu.',
]);
}
return response()->json([
'status' => true,
'data' => $exercise,
'message' => 'Lấy danh sách đề thi thành công.',
]);
}
}

@ -1,24 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class BlankResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'position' => $this->position,
'correct_answer' => $this->correct_answer,
'other_answers' => $this->other_answers,
];
}
}

@ -1,24 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ChoiceResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'content' => $this->content,
'is_correct' => $this->is_correct,
'position' => $this->position,
];
}
}

@ -1,27 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ExerciseResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->lesson_name,
'description' => $this->description,
'level' => $this->level_label,
'year' => $this->year,
'skills' => SkillResource::collection($this->whenLoaded('skills')),
'question_groups' => QuestionGroupResource::collection($this->whenLoaded('questionGroups')),
];
}
}

@ -1,23 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class QuestionGroupResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'content' => $this->content,
'questions' => QuestionResource::collection($this->whenLoaded('questions')),
];
}
}

@ -1,25 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class QuestionResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'content' => $this->content,
'score' => $this->score,
'explanation' => $this->explanation,
'hint' => $this->hint,
'type' => [
'code' => $this->type->code ?? null,
'name' => $this->type->name ?? null,
],
'choices' => $this->when($this->type->code === 'multiple_choice', ChoiceResource::collection($this->choices)),
'blanks' => $this->when($this->type->code !== 'multiple_choice', BlankResource::collection($this->blanks)),
];
}
}

@ -1,22 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class SkillResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name
];
}
}

@ -23,18 +23,6 @@ class Exercise extends Model
'media_object_id',
];
protected $appends = ['level_label'];
public function getLevelLabelAttribute()
{
return match ($this->level) {
0 => 'easy',
1 => 'normal',
2 => 'hard',
default => 'normal',
};
}
public function subject()
{
return $this->belongsTo(Subject::class, 'subject_id');

@ -17,10 +17,6 @@ class QuestionBlank extends Model
'other_answers',
];
protected $casts = [
'other_answers' => 'array', // Laravel tự động json_decode
];
public function question()
{
return $this->belongsTo(Question::class, 'question_id');

@ -15,7 +15,7 @@ class User extends Authenticatable
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasApiTokens, HasFactory, Notifiable, HasRoles;
protected $table = 'users';
protected $table = 'users_laravel';
/**
* The attributes that are mass assignable.

@ -2,7 +2,6 @@
namespace App\Services;
use App\Http\Resources\ExerciseResource;
use App\Models\Exercise;
class ExerciseService
@ -53,22 +52,4 @@ class ExerciseService
return $exercise->id;
}
public function detail($id)
{
$exercise = Exercise::with([
'skills:id,name',
'questionGroups' => function ($q) {
$q->select('id', 'exercise_id', 'content');
},
'questionGroups.questions' => function ($q) {
$q->select('id', 'content', 'group_id', 'question_type_id', 'description', 'score', 'explanation', 'hint');
},
'questionGroups.questions.type:id,code,name',
'questionGroups.questions.choices',
'questionGroups.questions.blanks',
])->findOrFail($id);
return new ExerciseResource($exercise);
}
}

@ -6,7 +6,6 @@ use App\Models\Question;
use App\Models\QuestionBlank;
use App\Models\QuestionChoice;
use App\Models\QuestionGroup;
use App\Models\QuestionType;
use Illuminate\Support\Facades\DB;
class QuestionService
@ -60,20 +59,19 @@ class QuestionService
foreach ($data as $groupKey => $value) {
$groupId = $groupIds[$groupKey];
foreach ($value->questions as $qIndex => $question) {
$questionType = QuestionType::where('code', $question->type)->first();
$questionTypeId = $questionType ? $questionType->id : 1;
$dataQuestion[] = [
'exercise_id' => $exerciseId,
'content' => $question->content,
'description' => $question->description ?? null,
'group_id' => $groupId,
'question_type_id' => $questionTypeId,
'question_type_id' => 1,
'level' => 2,
'score' => $question->score ?? null,
'explanation' => $question->explanation ?? null,
'hint' => $question->hint ?? null,
'created_at' => $now,
'updated_at' => $now
'updated_at' => $now,
'custom_key' => "{$groupKey}_{$qIndex}", // dùng để map lại
];
$questionMap["{$groupKey}_{$qIndex}"] = [
'type' => $question->type,

@ -13,7 +13,6 @@ Route::middleware(['auth:api', 'role:admin'])->get('/user', function (Request $r
});
Route::middleware('auth:api')->group(function () {
Route::get('/exercises', [ExerciseController::class, 'index'])->name('exercise.index');
Route::get('/exercise', [ExerciseController::class, 'index'])->name('exercise.index');
Route::post('/exercise/create', [ExerciseController::class, 'create'])->name('exercise.create');
Route::get('/exercise/{id}', [ExerciseController::class, 'detail'])->name('exercise.detail');
});

Loading…
Cancel
Save