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