Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
72 / 72
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
NewsController
100.00% covered (success)
100.00%
72 / 72
100.00% covered (success)
100.00%
5 / 5
19
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 edit
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 showEdit
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 save
100.00% covered (success)
100.00%
45 / 45
100.00% covered (success)
100.00%
1 / 1
11
 delete
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Engelsystem\Controllers\Admin;
6
7use Engelsystem\Controllers\BaseController;
8use Engelsystem\Controllers\HasUserNotifications;
9use Engelsystem\Controllers\NotificationType;
10use Engelsystem\Helpers\Authenticator;
11use Engelsystem\Http\Redirector;
12use Engelsystem\Http\Request;
13use Engelsystem\Http\Response;
14use Engelsystem\Models\News;
15use Engelsystem\Models\User\Settings;
16use Psr\Log\LoggerInterface;
17
18class NewsController extends BaseController
19{
20    use HasUserNotifications;
21
22    /** @var array<string> */
23    protected array $permissions = [
24        'admin_news',
25    ];
26
27    public function __construct(
28        protected Authenticator $auth,
29        protected LoggerInterface $log,
30        protected News $news,
31        protected Redirector $redirect,
32        protected Response $response
33    ) {
34    }
35
36    public function edit(Request $request): Response
37    {
38        $newsId = $request->getAttribute('news_id'); // optional
39
40        $news = $this->news->find($newsId);
41        $isMeeting = (bool) $request->get('meeting', false);
42
43        return $this->showEdit($news, !$news, $isMeeting);
44    }
45
46    protected function showEdit(?News $news, bool $sendNotification = true, bool $isMeetingDefault = false): Response
47    {
48        $notificationsCount = Settings::whereEmailNews(true)->count();
49        return $this->response->withView(
50            'pages/news/edit.twig',
51            [
52                'news'           => $news,
53                'is_meeting'     => $news ? $news->is_meeting : $isMeetingDefault,
54                'is_pinned'      => $news ? $news->is_pinned : false,
55                'is_highlighted' => $news ? $news->is_highlighted : false,
56                'send_notification' => $sendNotification,
57                'notifications_count' => $notificationsCount,
58            ],
59        );
60    }
61
62    public function save(Request $request): Response
63    {
64        $newsId = $request->getAttribute('news_id'); // optional
65
66        /** @var News $news */
67        $news = $this->news->findOrNew($newsId);
68
69        if ($request->request->has('delete')) {
70            return $this->delete($news);
71        }
72
73        $data = $this->validate($request, [
74            'title'          => 'required|max:150',
75            'text'           => 'required',
76            'is_meeting'     => 'optional|checked',
77            'is_pinned'      => 'optional|checked',
78            'is_highlighted' => 'optional|checked',
79            'delete'         => 'optional|checked',
80            'preview'        => 'optional|checked',
81            'send_notification' => 'optional|checked',
82        ]);
83
84        if (!$news->user) {
85            $news->user()->associate($this->auth->user());
86        }
87        $news->title = $data['title'];
88        $news->text = $data['text'];
89        $news->is_meeting = !is_null($data['is_meeting']);
90        $news->is_pinned = !is_null($data['is_pinned']);
91        $notify = !is_null($data['send_notification']);
92
93        if ($this->auth->can('news.highlight')) {
94            $news->is_highlighted = !is_null($data['is_highlighted']);
95        }
96
97        if (!is_null($data['preview'])) {
98            return $this->showEdit($news, $notify);
99        }
100
101        $isNewNews = !$news->id;
102        if ($isNewNews && News::where('title', $news->title)->where('text', $news->text)->count()) {
103            $this->addNotification('news.edit.duplicate', NotificationType::ERROR);
104            return $this->showEdit($news, $notify);
105        }
106        $news->save();
107
108        if ($isNewNews) {
109            event('news.created', ['news' => $news, 'sendNotification' => $notify]);
110        } else {
111            event('news.updated', ['news' => $news, 'sendNotification' => $notify]);
112        }
113
114        $this->log->info(
115            'Updated {pinned}{type} "{news}": {text}',
116            [
117                'pinned'    => $news->is_pinned ? 'pinned ' : '',
118                'highlighted' => $news->is_highlighted ? 'highlighted ' : '',
119                'type'      => $news->is_meeting ? 'meeting' : 'news',
120                'news'      => $news->title,
121                'text'      => $news->text,
122            ]
123        );
124
125        $this->addNotification('news.edit.success');
126
127        return $this->redirect->to('/news');
128    }
129
130    protected function delete(News $news): Response
131    {
132        $news->delete();
133
134        $this->log->info(
135            'Deleted {type} "{news}"',
136            [
137                'type' => $news->is_meeting ? 'meeting' : 'news',
138                'news' => $news->title,
139            ]
140        );
141
142        $this->addNotification('news.delete.success');
143
144        return $this->redirect->to('/news');
145    }
146}