Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
78.26% covered (warning)
78.26%
36 / 46
28.57% covered (danger)
28.57%
2 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
RecordCalendarApiController
80.00% covered (warning)
80.00%
36 / 45
28.57% covered (danger)
28.57%
2 / 7
20.59
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 actionCalendarEvents
86.36% covered (warning)
86.36%
19 / 22
0.00% covered (danger)
0.00%
0 / 1
6.09
 actionCalendarUsers
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
4.03
 actionRelatedCalendarEvents
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
2.26
 actionRelatedWorkTime
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
2.26
 assertPermissionContext
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 handleException
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Engine\Presentation\Api;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Shared\Infrastructure\Http\ApiResponseTrait;
12use App\Core\Engine\Application\Service\UniversalCrudService;
13use App\Core\Engine\Domain\Exception\ModuleNotFoundException;
14use App\Core\Engine\Domain\Exception\PermissionDeniedException;
15use App\Core\Engine\Domain\Exception\RecordNotFoundException;
16use App\Modules\Structure\Domain\Exception\StructureReassignRequiredException;
17use App\Core\Engine\Domain\Exception\ValidationException;
18use App\Core\Engine\Domain\Model\PermissionContext;
19use Nyholm\Psr7\Factory\Psr17Factory;
20use Psr\Http\Message\ResponseInterface;
21use Psr\Http\Message\ServerRequestInterface;
22
23/**
24 * Handles calendar-related API actions: events, users, related calendar events, and work time.
25 */
26final readonly class RecordCalendarApiController
27{
28    use ApiResponseTrait;
29
30    public function __construct(
31        private UniversalCrudService $crudService,
32        private Psr17Factory $psr17
33    ) {
34    }
35
36    /**
37     * Handles GET /api/v1/engine/{module}/calendar-events for calendar view rendering.
38     *
39     * @param ServerRequestInterface $request PSR-7 server request.
40     * @param string                 $module  Module machine name.
41     * @param PermissionContext      $context Security context.
42     * @return ResponseInterface JSON response with calendar events array.
43     */
44    public function actionCalendarEvents(
45        ServerRequestInterface $request,
46        string $module,
47        PermissionContext $context
48    ): ResponseInterface {
49        try {
50            $params   = $request->getQueryParams();
51            $start    = (string) ($params['start'] ?? date('Y-m-01 00:00:00'));
52            $end      = (string) ($params['end'] ?? date('Y-m-t 23:59:59'));
53            $filterId = isset($params['filter_id']) && is_numeric($params['filter_id'])
54                ? (int) $params['filter_id']
55                : null;
56            $userId = null;
57            if (isset($params['user_ids'])) {
58                $userId = (string) $params['user_ids'];
59            } elseif (isset($params['user_id'])) {
60                $userId = (string) $params['user_id'];
61            }
62
63            $events = $this->crudService->listCalendarEvents(
64                $module,
65                $start,
66                $end,
67                $context,
68                $filterId,
69                $userId
70            );
71
72            return $this->jsonSuccess($this->psr17, $events);
73        } catch (\Throwable $e) {
74            return $this->handleException($e);
75        }
76    }
77
78    /**
79     * Handles GET /api/v1/engine/{module}/calendar-users for calendar user filter panel.
80     *
81     * @param ServerRequestInterface $request PSR-7 server request.
82     * @param string                 $module  Module machine name.
83     * @param PermissionContext      $context Security context.
84     * @return ResponseInterface JSON response with users list matching active filter.
85     */
86    public function actionCalendarUsers(
87        ServerRequestInterface $request,
88        string $module,
89        PermissionContext $context
90    ): ResponseInterface {
91        try {
92            $params   = $request->getQueryParams();
93            $filterId = isset($params['filter_id']) && is_numeric($params['filter_id'])
94                ? (int) $params['filter_id']
95                : null;
96
97            $data = $this->crudService->listCalendarUsers($module, $context, $filterId);
98
99            return $this->jsonSuccess($this->psr17, $data);
100        } catch (\Throwable $e) {
101            return $this->handleException($e);
102        }
103    }
104
105    /**
106     * Handles GET /api/v1/engine/{module}/{id}/calendar-events for related calendar tab.
107     *
108     * @param ServerRequestInterface $request Incoming HTTP request.
109     * @param string                 $module  Parent module name.
110     * @param int                    $id      Parent record primary key.
111     * @param PermissionContext      $context User permission context.
112     * @return ResponseInterface JSON response with related events list.
113     */
114    public function actionRelatedCalendarEvents(
115        ServerRequestInterface $request,
116        string $module,
117        int $id,
118        PermissionContext $context
119    ): ResponseInterface {
120        try {
121            $this->assertPermissionContext($context, $request);
122            $events = $this->crudService->listRelatedCalendarEvents($module, $id);
123
124            return $this->jsonSuccess($this->psr17, $events);
125        } catch (\Throwable $e) {
126            return $this->handleException($e);
127        }
128    }
129
130    /**
131     * Handles GET /api/v1/engine/{module}/{id}/work-time-records for related work time tab.
132     *
133     * @param ServerRequestInterface $request Incoming HTTP request.
134     * @param string                 $module  Parent module name.
135     * @param int                    $id      Parent record primary key.
136     * @param PermissionContext      $context User permission context.
137     * @return ResponseInterface JSON response with related work time records.
138     */
139    public function actionRelatedWorkTime(
140        ServerRequestInterface $request,
141        string $module,
142        int $id,
143        PermissionContext $context
144    ): ResponseInterface {
145        try {
146            $this->assertPermissionContext($context, $request);
147            $result = $this->crudService->listRelatedWorkTimeRecords($module, $id);
148
149            return $this->jsonSuccess($this->psr17, $result);
150        } catch (\Throwable $e) {
151            return $this->handleException($e);
152        }
153    }
154
155    /**
156     * Validates permission context and request preconditions.
157     */
158    private function assertPermissionContext(PermissionContext $context, ServerRequestInterface $request): void
159    {
160        if ($context->actorUserId < 0) {
161            throw new \InvalidArgumentException('Invalid actor context');
162        }
163        $request->getMethod();
164    }
165
166    /**
167     * Maps thrown domain exceptions to PSR-7 JSON responses.
168     */
169    private function handleException(\Throwable $e): ResponseInterface
170    {
171        return $this->handleApiException($this->psr17, $e);
172    }
173}