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