Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create feedback CR #62

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/app/Enums/FeedbackQuestionType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace App\Enums;

use BenSampo\Enum\Enum;

final class FeedbackQuestionType extends Enum
{
public const TEXT = "text";
public const BOOLEAN = "boolean";
public const MCQ = "mcq";
}
33 changes: 33 additions & 0 deletions src/app/Http/Controllers/FeedbackController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace App\Http\Controllers;

use App\Http\Requests\FeedbackRequest;
use App\Services\FeedbackService;

class FeedbackController extends Controller
{
protected FeedbackService $service;

public function __construct(FeedbackService $feedbackService)
{
$this->middleware("permission:feedback.list", ["only" => ["index"]]);
$this->middleware("permission:feedback.retrieve", ["only" => ["show"]]);

$this->service = $feedbackService;
}

public function index(FeedbackRequest $request)
{
return view("feedback.index", [
"feedbacks" => $this->service->getAllFeedback($request->authUser)
]);
}

public function show(FeedbackRequest $request)
{
return view("feedback.retrieve", [
"feedback" => $request->feedback
]);
}
}
85 changes: 85 additions & 0 deletions src/app/Http/Controllers/FeedbackCourseController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace App\Http\Controllers;

use App\Enums\Roles;
use App\Exceptions\IntendedException;
use App\Http\Requests\FeedbackCourseRequest;
use App\Models\Feedback;
use App\Services\FeedbackService;

class FeedbackCourseController extends Controller
{
protected FeedbackService $service;

public function __construct(FeedbackService $feedbackService)
{
$this->middleware("role:" . Roles::STUDENT, ["only" => ["create", "store"]]);
$this->middleware("permission:feedback.list", ["only" => "index"]);
$this->service = $feedbackService;
}

public function index(FeedbackCourseRequest $request)
{
return view("feedback.index", [
"feedbacks" => $this->service->getAllFeedback($request->authUser, $request->course->id)
]);
}

public function create(FeedbackCourseRequest $request)
{
if ($this->service->isFeedbackComplete($request->authUser, $request->course->id)) {
abort(409, "You already completed feedback for this course");
}

return view("feedback.create", [
"courseId" => $request->course->id,
"faculties" => $request->course->faculties,
"format" => $request->course->getFeedbackFormat()
]);
}

public function store(FeedbackCourseRequest $request)
{
/*
* {
* faculty1_id: {
* <feedback data>
* },
* faculty_2_id: {
* <feedback data>
* }
* ...
* }
*/
$datas = $request->json("data");

if (!$this->service->verifyFaculties($datas, $request->course)) {
abort(400, "Invalid faculties");
}

if ($this->service->isFeedbackComplete($request->authUser, $request->course->id)) {
abort(409, "You already completed feedback for this course");
}

$feedbacks = array();
foreach ($datas as $faculty_id => $facultyFeedback) {
try {
$feedbackData = $this->service->combineFeedbackWithFormat($facultyFeedback, $request->course);
} catch (IntendedException $e) {
abort(400, $e->getMessage());
}
array_push($feedbacks, [
// Eloquent isn't used for bulk insert so mutators won't work, so format manually
"data" => json_encode($feedbackData),
"faculty_id" => $faculty_id,
"course_id" => $request->course->id
]);
}
// Bulk insert feedback and set feedback to complete
Feedback::insert($feedbacks);
$request->authUser->student->finishFeedback($request->course->id);

return response("OK");
}
}
47 changes: 47 additions & 0 deletions src/app/Http/Requests/FeedbackCourseRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Http\Requests;

use App\Models\Course;
use App\Models\Curriculum;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;

class FeedbackCourseRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
$this->authUser = Auth::user();
$courseId = $this->route()->parameter("course_id");
$this->course = Course::findOrFail($courseId);
$this->courseCurriculum = Curriculum::where([
"student_admission_id" => $this->authUser->student_admission_id,
"course_id" => $courseId
])->first();

if ($this->route()->getName() == "faculties.courses.index") {
return true;
}

return $this->authUser->student->hasCourse($courseId)
&& !$this->courseCurriculum->is_feedback_completed
&& $this->course->is_feedback_open;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}
45 changes: 45 additions & 0 deletions src/app/Http/Requests/FeedbackRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace App\Http\Requests;

use App\Models\Feedback;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;

class FeedbackRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
$this->authUser = Auth::user();
if ($this->route()->getName() == "feedbacks.show") {
$this->feedback = Feedback::findOrFail($this->route()->parameter("feedback"));

$canViewEverything = $this->authUser->faculty?->isPrincipal() || $this->authUser->isAdmin();

$isHODAndSameDepartment = $this->authUser->faculty?->isHOD() &&
$this->feedback->course->department_code == $this->authUser->faculty?->department_code;

$isSameFaculty = $this->authUser->faculty_id == $this->feedback->faculty_id;

return $canViewEverything || $isHODAndSameDepartment || $isSameFaculty;
}
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}
33 changes: 32 additions & 1 deletion src/app/Models/Course.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Models;

use App\Enums\CourseTypes;
use App\Enums\FeedbackQuestionType;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
Expand All @@ -18,11 +19,36 @@ class Course extends Model
protected $guarded = [
'semester',
'type',
'active' => true
'active' => true,
'is_feedback_open' => false
];

protected $with = ["faculties"];

static array $defaultFeedbackFormat = [
[
"question" => "Question 1",
"type" => FeedbackQuestionType::MCQ,
"options" => [
["string" => "option1", "score" => 1],
["string" => "option2", "score" => 2],
["string" => "option3", "score" => 3],
["string" => "option4", "score" => 4],
],
"required" => true
],
[
"question" => "Question 2",
"type" => FeedbackQuestionType::BOOLEAN,
"required" => true
],
[
"question" => "Question 3",
"type" => FeedbackQuestionType::TEXT,
"required" => true
],
];

public function faculties(): BelongsToMany
{
return $this->belongsToMany(Faculty::class, "faculty_course");
Expand Down Expand Up @@ -73,4 +99,9 @@ public static function getBaseQuery()
{
return Course::with("subject")->where("active", true);
}

public function getFeedbackFormat(): array
{
return json_decode($this->feedback_format) ?? Course::$defaultFeedbackFormat;
}
}
2 changes: 1 addition & 1 deletion src/app/Models/Department.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function classrooms()
return $this->hasMany(Classroom::class);
}

public function getHOD()
public function getHOD(): Faculty
{
return $this->faculties->first(function ($value, $_) {
return $value->user->hasRole(Roles::HOD);
Expand Down
45 changes: 45 additions & 0 deletions src/app/Models/Feedback.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Feedback extends Model
{
use HasFactory;

protected $fillable = [
"data"
];

static array $testFeedback = [
3,
0,
"testing the system"
];

public $timestamps = false;

protected $table = "feedbacks";

protected $with = ["course", "faculty"];

protected $casts = ["data" => "json"];

public function setDataAttribute($data)
{
$this->attributes["data"] = json_encode($data);
}

public function course(): BelongsTo
{
return $this->belongsTo(Course::class);
}

public function faculty(): BelongsTo
{
return $this->belongsTo(Faculty::class);
}
}
25 changes: 25 additions & 0 deletions src/app/Models/Student.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,37 @@ public function classroom()
return $this->belongsTo(Classroom::class);
}

public function curriculums()
{
return $this->hasMany(Curriculum::class);
}

public function semester()
{
return $this->classroom->semester;
}

public function department()
{
return $this->classroom->department;
}

public function hasCourse($courseId): bool
{
$targetCourse = $this?->curriculums?->map(function ($curriculum) {
return $curriculum->course_id;
})?->filter(function ($studentCourseId) use ($courseId) {
return $studentCourseId == $courseId;
});

return $targetCourse != null && !$targetCourse->isEmpty();
}

public function finishFeedback($courseId)
{
echo json_encode($this->curriculums);
$targetCurriculum = $this->curriculums->firstWhere("course_id", $courseId);
$targetCurriculum->is_feedback_complete = true;
$targetCurriculum->save();
}
}
Loading