Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 107 |
|
0.00% |
0 / 13 |
CRAP | |
0.00% |
0 / 1 |
NewsEndpointTrait | |
0.00% |
0 / 107 |
|
0.00% |
0 / 13 |
1482 | |
0.00% |
0 / 1 |
configureNewsEndpointTrait | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getEntityData | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
30 | |||
updateEntityWithData | |
0.00% |
0 / 35 |
|
0.00% |
0 / 1 |
30 | |||
persistUploads | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
editUploads | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getEntityById | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
getFormat | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getFormatForApi | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
72 | |||
getAuthorUserId | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
getAuthorRoleId | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
getTerminId | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
getTagsForDb | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTagsForApi | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | namespace Olz\News\Endpoints; |
4 | |
5 | use Olz\Entity\News\NewsEntry; |
6 | use Olz\Entity\Roles\Role; |
7 | use Olz\Entity\Users\User; |
8 | use Olz\Utils\WithUtilsTrait; |
9 | use PhpTypeScriptApi\HttpError; |
10 | use PhpTypeScriptApi\PhpStan\IsoDateTime; |
11 | |
12 | /** |
13 | * @phpstan-type OlzNewsId int |
14 | * @phpstan-type OlzNewsData array{ |
15 | * format: OlzNewsFormat, |
16 | * authorUserId?: ?int<1, max>, |
17 | * authorRoleId?: ?int<1, max>, |
18 | * authorName?: ?non-empty-string, |
19 | * authorEmail?: ?non-empty-string, |
20 | * publishAt?: ?IsoDateTime, |
21 | * title: non-empty-string, |
22 | * teaser: string, |
23 | * content: string, |
24 | * externalUrl?: ?non-empty-string, |
25 | * tags: array<non-empty-string>, |
26 | * terminId?: ?int<1, max>, |
27 | * imageIds?: ?array<non-empty-string>, |
28 | * fileIds: array<non-empty-string>, |
29 | * } |
30 | * @phpstan-type OlzNewsFormat 'aktuell'|'kaderblog'|'forum'|'galerie'|'video'|'anonymous' |
31 | */ |
32 | trait NewsEndpointTrait { |
33 | use WithUtilsTrait; |
34 | |
35 | public function configureNewsEndpointTrait(): void { |
36 | $this->phpStanUtils->registerApiObject(IsoDateTime::class); |
37 | } |
38 | |
39 | /** @return OlzNewsData */ |
40 | public function getEntityData(NewsEntry $entity): array { |
41 | $author_name = $entity->getAuthorName(); |
42 | $author_email = $entity->getAuthorEmail(); |
43 | $published_date = $entity->getPublishedDate()->format('Y-m-d'); |
44 | $published_time = $entity->getPublishedTime()?->format('H:i:s') ?? '00:00:00'; |
45 | $tags_for_api = $this->getTagsForApi($entity->getTags()); |
46 | $external_url = $entity->getExternalUrl(); |
47 | $termin_id = $entity->getTermin(); |
48 | |
49 | $valid_image_ids = $this->uploadUtils()->getValidUploadIds($entity->getImageIds()); |
50 | $file_ids = $entity->getStoredFileUploadIds(); |
51 | |
52 | return [ |
53 | 'format' => $this->getFormatForApi($entity), |
54 | 'authorUserId' => $this->getAuthorUserId($entity), |
55 | 'authorRoleId' => $this->getAuthorRoleId($entity), |
56 | 'authorName' => $author_name ? $author_name : null, |
57 | 'authorEmail' => $author_email ? $author_email : null, |
58 | 'publishAt' => new IsoDateTime("{$published_date} {$published_time}"), |
59 | 'title' => $entity->getTitle() ?: '-', |
60 | 'teaser' => $entity->getTeaser() ?? '', |
61 | 'content' => $entity->getContent() ?? '', |
62 | 'externalUrl' => $external_url ? $external_url : null, |
63 | 'tags' => $tags_for_api, |
64 | 'terminId' => $this->getTerminId($entity), |
65 | 'imageIds' => $valid_image_ids, |
66 | 'fileIds' => $file_ids, |
67 | ]; |
68 | } |
69 | |
70 | /** @param OlzNewsData $input_data */ |
71 | public function updateEntityWithData(NewsEntry $entity, array $input_data): void { |
72 | $user_repo = $this->entityManager()->getRepository(User::class); |
73 | $role_repo = $this->entityManager()->getRepository(Role::class); |
74 | $current_user = $this->authUtils()->getCurrentUser(); |
75 | $now = new \DateTime($this->dateUtils()->getIsoNow()); |
76 | |
77 | $author_user_id = $input_data['authorUserId'] ?? null; |
78 | $author_user = $current_user; |
79 | if ($author_user_id) { |
80 | $author_user = $user_repo->findOneBy(['id' => $author_user_id]); |
81 | } |
82 | |
83 | $author_role_id = $input_data['authorRoleId'] ?? null; |
84 | $author_role = null; |
85 | if ($author_role_id) { |
86 | $is_admin = $this->authUtils()->hasPermission('all'); |
87 | $is_authenticated_role = $this->authUtils()->isRoleIdAuthenticated($author_role_id); |
88 | if (!$is_authenticated_role && !$is_admin) { |
89 | throw new HttpError(403, "Kein Zugriff auf Autor-Rolle!"); |
90 | } |
91 | $author_role = $role_repo->findOneBy(['id' => $author_role_id]); |
92 | } |
93 | |
94 | $publish_at = $input_data['publishAt'] ?? $now; |
95 | |
96 | $tags_for_db = $this->getTagsForDb($input_data['tags']); |
97 | $valid_image_ids = $this->uploadUtils()->getValidUploadIds($input_data['imageIds'] ?? null); |
98 | |
99 | $entity->setAuthorUser($author_user); |
100 | $entity->setAuthorRole($author_role); |
101 | $entity->setAuthorName($input_data['authorName'] ?? null); |
102 | $entity->setAuthorEmail($input_data['authorEmail'] ?? null); |
103 | $entity->setPublishedDate($publish_at); |
104 | $entity->setPublishedTime($publish_at); |
105 | $entity->setTitle($input_data['title']); |
106 | $entity->setTeaser($input_data['teaser']); |
107 | $entity->setContent($input_data['content']); |
108 | $entity->setExternalUrl($input_data['externalUrl'] ?? null); |
109 | $entity->setTags($tags_for_db); |
110 | $entity->setImageIds($valid_image_ids); |
111 | // TODO: Do not ignore |
112 | $entity->setTermin(0); |
113 | $entity->setCounter(0); |
114 | $entity->setFormat($this->getFormat($input_data['format'])); |
115 | $entity->setNewsletter(true); |
116 | } |
117 | |
118 | /** @param OlzNewsData $input_data */ |
119 | public function persistUploads(NewsEntry $entity, array $input_data): void { |
120 | $this->persistOlzImages($entity, $entity->getImageIds()); |
121 | $this->persistOlzFiles($entity, $input_data['fileIds']); |
122 | } |
123 | |
124 | public function editUploads(NewsEntry $entity): void { |
125 | $this->editOlzImages($entity, $entity->getImageIds()); |
126 | $this->editOlzFiles($entity); |
127 | } |
128 | |
129 | protected function getEntityById(int $id): NewsEntry { |
130 | $news_repo = $this->entityManager()->getRepository(NewsEntry::class); |
131 | $entity = $news_repo->findOneBy(['id' => $id]); |
132 | if (!$entity) { |
133 | throw new HttpError(404, "Nicht gefunden."); |
134 | } |
135 | return $entity; |
136 | } |
137 | |
138 | // --- |
139 | |
140 | protected function getFormat(string $format): string { |
141 | if ($format === 'anonymous') { |
142 | return 'forum'; |
143 | } |
144 | return $format; |
145 | } |
146 | |
147 | /** @return OlzNewsFormat */ |
148 | protected function getFormatForApi(NewsEntry $entity): string { |
149 | switch ($entity->getFormat()) { |
150 | case 'aktuell': return 'aktuell'; |
151 | case 'anonymous': return 'anonymous'; |
152 | case 'forum': return 'forum'; |
153 | case 'galerie': return 'galerie'; |
154 | case 'kaderblog': return 'kaderblog'; |
155 | case 'video': return 'video'; |
156 | default: throw new \Exception("Unknown news format: {$entity->getFormat()} ({$entity})"); |
157 | } |
158 | } |
159 | |
160 | /** @return ?int<1, max> */ |
161 | protected function getAuthorUserId(NewsEntry $entity): ?int { |
162 | $number = $entity->getAuthorUser()?->getId(); |
163 | if ($number === null) { |
164 | return null; |
165 | } |
166 | if ($number < 1) { |
167 | throw new \Exception("Invalid author user ID: {$number} ({$entity})"); |
168 | } |
169 | return $number; |
170 | } |
171 | |
172 | /** @return ?int<1, max> */ |
173 | protected function getAuthorRoleId(NewsEntry $entity): ?int { |
174 | $number = $entity->getAuthorRole()?->getId(); |
175 | if ($number === null) { |
176 | return null; |
177 | } |
178 | if ($number < 1) { |
179 | throw new \Exception("Invalid author role ID: {$number} ({$entity})"); |
180 | } |
181 | return $number; |
182 | } |
183 | |
184 | /** @return ?int<1, max> */ |
185 | protected function getTerminId(NewsEntry $entity): ?int { |
186 | $number = $entity->getTermin(); |
187 | if (!$number) { |
188 | return null; |
189 | } |
190 | if ($number < 1) { |
191 | throw new \Exception("Invalid termin ID: {$number} ({$entity})"); |
192 | } |
193 | return $number; |
194 | } |
195 | |
196 | /** @param array<string> $tags */ |
197 | protected function getTagsForDb(?array $tags): string { |
198 | return ' '.implode(' ', $tags ?? []).' '; |
199 | } |
200 | |
201 | /** @return array<non-empty-string> */ |
202 | protected function getTagsForApi(?string $tags): array { |
203 | $tags_string = $tags ?? ''; |
204 | $tags_for_api = []; |
205 | foreach (explode(' ', $tags_string) as $tag) { |
206 | $trimmed = trim($tag); |
207 | if ($trimmed) { |
208 | $tags_for_api[] = $trimmed; |
209 | } |
210 | } |
211 | return $tags_for_api; |
212 | } |
213 | } |