Files
alrahma_sunday_school_api/app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php
T
2026-06-09 01:03:53 -04:00

283 lines
10 KiB
PHP

<?php
namespace App\Http\Controllers\Api\PrintRequests;
use App\Http\Controllers\Api\Core\BaseApiController;
use App\Models\PrintRequest;
use App\Models\User;
use App\Services\PrintRequests\PrintRequestsPortalService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Response;
class PrintRequestsController extends BaseApiController
{
public function __construct(
private PrintRequestsPortalService $portal,
) {
parent::__construct();
}
public function teacher(): JsonResponse
{
$uid = $this->getCurrentUserId();
if (! $uid) {
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
}
return $this->success($this->portal->teacherBootstrap($uid));
}
public function admin(): JsonResponse
{
return $this->success([
'print_requests' => $this->portal->adminPrintRequests(),
]);
}
public function store(Request $request): JsonResponse
{
$uid = $this->getCurrentUserId();
if (! $uid) {
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
}
$validator = Validator::make($request->all(), [
'file' => ['required', 'file', 'max:5120', 'mimes:pdf,jpg,jpeg,png,doc,docx,txt', 'mimetypes:application/pdf,image/jpeg,image/png,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
'page_selection' => ['nullable', 'string', 'regex:/^\s*\d+(?:\s*-\s*\d+)?(?:\s*,\s*\d+(?:\s*-\s*\d+)?)*\s*$/'],
'num_copies' => ['required', 'integer', 'min:1'],
'required_by' => ['required', 'date'],
'pickup_method' => ['required', 'string', 'max:255'],
'class_id' => ['required', 'integer', 'min:1'],
]);
if ($validator->fails()) {
return $this->respondValidationError($validator->errors()->toArray());
}
/** @var \Illuminate\Http\UploadedFile $file */
$file = $request->file('file');
$model = $this->portal->storeTeacherUpload($validator->validated(), $file, $uid);
return $this->respondCreated(
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
'Print request created successfully.'
);
}
public function teacherUpdate(Request $request, int $id): JsonResponse
{
$uid = $this->getCurrentUserId();
if (! $uid) {
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
}
$pr = PrintRequest::query()->find($id);
if (! $pr) {
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
}
if (! $this->portal->teacherOwnsRequest($pr, $uid)) {
return $this->error('You are not authorized to edit this request.', Response::HTTP_FORBIDDEN);
}
if (! $this->portal->teacherMayEditOrDelete($pr)) {
return $this->error('Cannot edit a request that is already being processed.', Response::HTTP_BAD_REQUEST);
}
$rules = [
'num_copies' => ['required', 'integer', 'min:1'],
'required_by' => ['required', 'date'],
'pickup_method' => ['required', 'string', Rule::in(['Self Pickup', 'Delivered to class'])],
'page_selection' => ['nullable', 'string', 'regex:/^\s*\d+(?:\s*-\s*\d+)?(?:\s*,\s*\d+(?:\s*-\s*\d+)?)*\s*$/'],
];
if ($request->hasFile('file') && $request->file('file')->isValid()) {
$rules['file'] = ['required', 'file', 'max:5120', 'mimes:pdf,jpg,jpeg,png,doc,docx,txt', 'mimetypes:application/pdf,image/jpeg,image/png,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
}
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
return $this->respondValidationError($validator->errors()->toArray());
}
$data = $validator->validated();
$newFile = ($request->hasFile('file') && $request->file('file')->isValid())
? $request->file('file')
: null;
$model = $this->portal->updateTeacherFields($pr, $data, $newFile);
return $this->success(
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
'Print request updated successfully.'
);
}
public function adminStatus(Request $request, int $id): JsonResponse
{
$uid = $this->getCurrentUserId();
if (! $uid) {
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
}
$validator = Validator::make($request->all(), [
'status' => ['required', 'string', Rule::in(['not_assigned', 'assigned', 'done', 'delivered'])],
]);
if ($validator->fails()) {
return $this->respondValidationError($validator->errors()->toArray());
}
$pr = PrintRequest::query()->find($id);
if (! $pr) {
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
}
$newStatus = (string) $validator->validated()['status'];
try {
$model = $this->portal->applyAdminStatus($pr, $newStatus, $uid);
} catch (\InvalidArgumentException $e) {
return $this->error($e->getMessage(), Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->success(
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
'Status updated successfully.'
);
}
public function destroy(int $id): JsonResponse
{
$uid = $this->getCurrentUserId();
if (! $uid) {
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
}
$pr = PrintRequest::query()->find($id);
if (! $pr) {
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
}
if (! $this->portal->teacherOwnsRequest($pr, $uid)) {
return $this->error('You are not authorized to delete this request.', Response::HTTP_FORBIDDEN);
}
if (! $this->portal->teacherMayEditOrDelete($pr)) {
return $this->error('Cannot delete a request that is already being processed.', Response::HTTP_BAD_REQUEST);
}
$this->portal->deleteTeacherRequest($pr);
return $this->respondDeleted(null, 'Print request deleted successfully.');
}
public function copy(int $id): JsonResponse
{
$uid = $this->getCurrentUserId();
if (! $uid) {
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
}
$pr = PrintRequest::query()->find($id);
if (! $pr) {
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
}
if (! $this->portal->teacherOwnsRequest($pr, $uid)) {
return $this->error('You are not authorized to copy this request.', Response::HTTP_FORBIDDEN);
}
try {
$model = $this->portal->copyFromExisting($pr, $uid);
} catch (\InvalidArgumentException $e) {
return $this->error($e->getMessage(), Response::HTTP_BAD_REQUEST);
}
return $this->respondCreated(
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
'Print request copied successfully.'
);
}
public function handCopy(Request $request): JsonResponse
{
$uid = $this->getCurrentUserId();
if (! $uid) {
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
}
$validator = Validator::make($request->all(), [
'num_copies' => ['required', 'integer', 'min:1'],
'required_by' => ['required', 'date'],
'pickup_method' => ['required', 'string', 'max:255'],
'class_id' => ['required', 'integer', 'min:1'],
]);
if ($validator->fails()) {
return $this->respondValidationError($validator->errors()->toArray());
}
$model = $this->portal->storeHandCopy($validator->validated(), $uid);
return $this->respondCreated(
['print_request' => $this->portal->normalizePrintRequestRow($model->toArray())],
'Copy request submitted. Please hand the original document to the copy center.'
);
}
public function download(int $id): BinaryFileResponse|JsonResponse
{
$uid = $this->getCurrentUserId();
if (! $uid) {
return $this->error('Unauthorized.', Response::HTTP_UNAUTHORIZED);
}
$pr = PrintRequest::query()->find($id);
if (! $pr) {
return $this->error('Print request not found.', Response::HTTP_NOT_FOUND);
}
$isAdmin = $this->userHasPrintAdminRole(Auth::user());
if (! $this->portal->authorizeDownload($pr, $uid, $isAdmin)) {
return $this->error('Forbidden.', Response::HTTP_FORBIDDEN);
}
$path = $this->portal->absolutePathForDownload($pr);
if ($path === null || ! is_readable($path)) {
return $this->error('File not found.', Response::HTTP_NOT_FOUND);
}
$mime = @mime_content_type($path) ?: 'application/octet-stream';
$safe = basename($path);
return response()->download($path, $safe, [
'Content-Type' => $mime,
]);
}
private function userHasPrintAdminRole(?User $user): bool
{
if (! $user) {
return false;
}
$roles = $user->roles()
->pluck('roles.name')
->map(fn ($name) => strtolower((string) $name))
->toArray();
foreach (['administrator', 'admin', 'principal', 'vice_principal', 'vice-principal'] as $allowed) {
if (in_array($allowed, $roles, true)) {
return true;
}
}
return false;
}
}