283 lines
9.7 KiB
PHP
283 lines
9.7 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'],
|
|
'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'];
|
|
}
|
|
|
|
$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;
|
|
}
|
|
}
|