Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 107
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
feed
0.00% covered (danger)
0.00%
0 / 107
0.00% covered (danger)
0.00%
0 / 13
2550
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 forums
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 news
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 topics
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 topics_new
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 topics_active
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 forum
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 topic
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 overall
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 send_feed
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 send_feed_do
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
812
 check_enabled
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 send_unavailable
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14namespace phpbb\feed\controller;
15
16use phpbb\auth\auth;
17use phpbb\config\config;
18use phpbb\db\driver\driver_interface;
19use phpbb\event\dispatcher_interface;
20use phpbb\exception\http_exception;
21use phpbb\feed\feed_interface;
22use phpbb\feed\exception\feed_unavailable_exception;
23use phpbb\feed\exception\unauthorized_exception;
24use phpbb\feed\helper as feed_helper;
25use phpbb\controller\helper as controller_helper;
26use phpbb\symfony_request;
27use phpbb\user;
28use phpbb\language\language;
29use Symfony\Component\DependencyInjection\ContainerInterface;
30use Symfony\Component\HttpFoundation\Response;
31use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
32use Twig\Environment;
33
34class feed
35{
36    /**
37     * @var Environment
38     */
39    protected $template;
40
41    /**
42     * @var symfony_request
43     */
44    protected $request;
45
46    /**
47     * @var controller_helper
48     */
49    protected $controller_helper;
50
51    /**
52     * @var config
53     */
54    protected $config;
55
56    /**
57     * @var driver_interface
58     */
59    protected $db;
60
61    /**
62     * @var ContainerInterface
63     */
64    protected $container;
65
66    /**
67     * @var feed_helper
68     */
69    protected $feed_helper;
70
71    /**
72     * @var user
73     */
74    protected $user;
75
76    /**
77     * @var auth
78     */
79    protected $auth;
80
81    /**
82     * @var dispatcher_interface
83     */
84    protected $phpbb_dispatcher;
85
86    /**
87     * @var string
88     */
89    protected $php_ext;
90
91    /**
92     * @var language
93     */
94    protected $language;
95
96    /**
97     * Constructor
98     *
99     * @param Environment $twig
100     * @param symfony_request $request
101     * @param controller_helper $controller_helper
102     * @param config $config
103     * @param driver_interface $db
104     * @param ContainerInterface $container
105     * @param feed_helper $feed_helper
106     * @param user $user
107     * @param auth $auth
108     * @param dispatcher_interface $phpbb_dispatcher
109     * @param language $language
110     * @param string $php_ext
111     */
112    public function __construct(Environment $twig, symfony_request $request, controller_helper $controller_helper, config $config, driver_interface $db, ContainerInterface $container, feed_helper $feed_helper, user $user, auth $auth, dispatcher_interface $phpbb_dispatcher, language $language, $php_ext)
113    {
114        $this->request = $request;
115        $this->controller_helper = $controller_helper;
116        $this->config = $config;
117        $this->db = $db;
118        $this->container = $container;
119        $this->feed_helper = $feed_helper;
120        $this->user = $user;
121        $this->auth = $auth;
122        $this->php_ext = $php_ext;
123        $this->template = $twig;
124        $this->language = $language;
125        $this->phpbb_dispatcher = $phpbb_dispatcher;
126    }
127
128    /**
129     * Controller for /feed/forums route
130     *
131     * @return Response
132     *
133     * @throws http_exception when the feed is disabled
134     */
135    public function forums()
136    {
137        $this->check_enabled();
138
139        if (!$this->config['feed_overall_forums'])
140        {
141            $this->send_unavailable();
142        }
143
144        return $this->send_feed($this->container->get('feed.forums'));
145    }
146
147    /**
148     * Controller for /feed/news route
149     *
150     * @return Response
151     *
152     * @throws http_exception when the feed is disabled
153     */
154    public function news()
155    {
156        $this->check_enabled();
157
158        // Get at least one news forum
159        $sql = 'SELECT forum_id
160                    FROM ' . FORUMS_TABLE . '
161                    WHERE ' . $this->db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0');
162        $result = $this->db->sql_query_limit($sql, 1, 0, 600);
163        $s_feed_news = (int) $this->db->sql_fetchfield('forum_id');
164        $this->db->sql_freeresult($result);
165
166        if (!$s_feed_news)
167        {
168            $this->send_unavailable();
169        }
170
171        return $this->send_feed($this->container->get('feed.news'));
172    }
173
174    /**
175     * Controller for /feed/topics route
176     *
177     * @return Response
178     *
179     * @throws http_exception when the feed is disabled
180     */
181    public function topics()
182    {
183        $this->check_enabled();
184
185        if (!$this->config['feed_topics_new'])
186        {
187            $this->send_unavailable();
188        }
189
190        return $this->send_feed($this->container->get('feed.topics'));
191    }
192
193    /**
194     * Controller for /feed/topics_new route
195     *
196     * @return Response
197     *
198     * @throws http_exception when the feed is disabled
199     */
200    public function topics_new()
201    {
202        $this->check_enabled();
203
204        return $this->topics();
205    }
206
207    /**
208     * Controller for /feed/topics_active route
209     *
210     * @return Response
211     *
212     * @throws http_exception when the feed is disabled
213     */
214    public function topics_active()
215    {
216        $this->check_enabled();
217
218        if (!$this->config['feed_topics_active'])
219        {
220            $this->send_unavailable();
221        }
222
223        return $this->send_feed($this->container->get('feed.topics_active'));
224    }
225
226    /**
227     * Controller for /feed/forum/{forum_id} route
228     *
229     * @param int $forum_id
230     *
231     * @return Response
232     *
233     * @throws http_exception when the feed is disabled
234     */
235    public function forum($forum_id)
236    {
237        $this->check_enabled();
238
239        if (!$this->config['feed_forum'])
240        {
241            $this->send_unavailable();
242        }
243
244        return $this->send_feed($this->container->get('feed.forum')->set_forum_id($forum_id));
245    }
246
247    /**
248     * Controller for /feed/topic/{topic_id} route
249     *
250     * @param int $topic_id
251     *
252     * @return Response
253     *
254     * @throws http_exception when the feed is disabled
255     */
256    public function topic($topic_id)
257    {
258        $this->check_enabled();
259
260        if (!$this->config['feed_topic'])
261        {
262            $this->send_unavailable();
263        }
264
265        return $this->send_feed($this->container->get('feed.topic')->set_topic_id($topic_id));
266    }
267
268    /**
269     * Controller for /feed/{mode] route
270     *
271     * @return Response
272     *
273     * @throws http_exception when the feed is disabled
274     */
275    public function overall()
276    {
277        $this->check_enabled();
278
279        if (!$this->config['feed_overall'])
280        {
281            $this->send_unavailable();
282        }
283
284        return $this->send_feed($this->container->get('feed.overall'));
285    }
286
287    /**
288     * Display a given feed
289     *
290     * @param feed_interface $feed
291     *
292     * @return Response
293     */
294    protected function send_feed(feed_interface $feed)
295    {
296        try
297        {
298            return $this->send_feed_do($feed);
299        }
300        catch (feed_unavailable_exception $e)
301        {
302            throw new http_exception(Response::HTTP_NOT_FOUND, $e->getMessage(), $e->get_parameters(), $e);
303        }
304        catch (unauthorized_exception $e)
305        {
306            throw new http_exception(Response::HTTP_FORBIDDEN, $e->getMessage(), $e->get_parameters(), $e);
307        }
308    }
309
310    /**
311     * Really send the feed
312     *
313     * @param feed_interface $feed
314     *
315     * @return Response
316     *
317     * @throws \phpbb\feed\exception\feed_exception
318     */
319    protected function send_feed_do(feed_interface $feed)
320    {
321        $feed_updated_time = 0;
322        $item_vars = array();
323        $this->language->add_lang('viewtopic');
324
325        $board_url = $this->feed_helper->get_board_url();
326
327        // Open Feed
328        $feed->open();
329
330        // Iterate through items
331        while ($row = $feed->get_item())
332        {
333            /**
334             * Event to modify the feed row
335             *
336             * @event core.feed_modify_feed_row
337             * @var    feed_interface feed Feed instance
338             * @var    array    row            Array with feed data
339             *
340             * @since 3.1.10-RC1
341             * @changed 3.3.0 Replace forum_id, mode, topic_id with feed instance
342             */
343            $vars = array('feed', 'row');
344            extract($this->phpbb_dispatcher->trigger_event('core.feed_modify_feed_row', compact($vars)));
345
346            // BBCode options to correctly disable urls, smilies, bbcode...
347            if ($feed->get('options') === null)
348            {
349                // Allow all combinations
350                $options = 7;
351
352                if ($feed->get('enable_bbcode') !== null && $feed->get('enable_smilies') !== null && $feed->get('enable_magic_url') !== null)
353                {
354                    $options = (($row[$feed->get('enable_bbcode')]) ? OPTION_FLAG_BBCODE : 0) + (($row[$feed->get('enable_smilies')]) ? OPTION_FLAG_SMILIES : 0) + (($row[$feed->get('enable_magic_url')]) ? OPTION_FLAG_LINKS : 0);
355                }
356            }
357            else
358            {
359                $options = $row[$feed->get('options')];
360            }
361
362            $title = (isset($row[$feed->get('title')]) && $row[$feed->get('title')] !== '') ? $row[$feed->get('title')] : ((isset($row[$feed->get('title2')])) ? $row[$feed->get('title2')] : '');
363
364            $published = ($feed->get('published') !== null) ? (int) $row[$feed->get('published')] : 0;
365            $updated = ($feed->get('updated') !== null) ? (int) $row[$feed->get('updated')] : 0;
366
367            $display_attachments = ($this->auth->acl_get('u_download') && $this->auth->acl_get('f_download', $row['forum_id']) && isset($row['post_attachment']) && $row['post_attachment']) ? true : false;
368
369            $item_row = array(
370                'author'        => ($feed->get('creator') !== null) ? $row[$feed->get('creator')] : '',
371                'published'        => ($published > 0) ? $this->feed_helper->format_date($published) : '',
372                'updated'        => ($updated > 0) ? $this->feed_helper->format_date($updated) : '',
373                'link'            => '',
374                'title'            => censor_text($title),
375                'category'        => ($this->config['feed_item_statistics'] && !empty($row['forum_id'])) ? $board_url . '/viewforum.' . $this->php_ext . '?f=' . $row['forum_id'] : '',
376                'category_name'    => ($this->config['feed_item_statistics'] && isset($row['forum_name'])) ? $row['forum_name'] : '',
377                'description'    => censor_text($this->feed_helper->generate_content($row[$feed->get('text')], $row[$feed->get('bbcode_uid')], $row[$feed->get('bitfield')], $options, $row['forum_id'], ($display_attachments ? $feed->get_attachments($row['post_id']) : array()))),
378                'statistics'    => '',
379            );
380
381            // Adjust items, fill link, etc.
382            $feed->adjust_item($item_row, $row);
383
384            $item_vars[] = $item_row;
385
386            $feed_updated_time = max($feed_updated_time, $published, $updated);
387        }
388
389        // If we do not have any items at all, sending the current time is better than sending no time.
390        if (!$feed_updated_time)
391        {
392            $feed_updated_time = time();
393        }
394
395        $feed->close();
396
397        $content = $this->template->render('feed.xml.twig', array(
398            // Some default assignments
399            // FEED_IMAGE is not used (atom)
400            'FEED_IMAGE'            => '',
401            'SELF_LINK'                => $this->controller_helper->route($this->request->attributes->get('_route'), $this->request->attributes->get('_route_params'), true, '', UrlGeneratorInterface::ABSOLUTE_URL),
402            'FEED_LINK'                => $board_url . '/index.' . $this->php_ext,
403            'FEED_TITLE'            => $this->config['sitename'],
404            'FEED_SUBTITLE'            => $this->config['site_desc'],
405            'FEED_UPDATED'            => $this->feed_helper->format_date($feed_updated_time),
406            'FEED_LANG'                => $this->language->lang('USER_LANG'),
407            'FEED_AUTHOR'            => $this->config['sitename'],
408
409            // Feed entries
410            'FEED_ROWS'                => $item_vars,
411        ));
412
413        $response = new Response($content);
414        $response->headers->set('Content-Type', 'application/atom+xml; charset=UTF-8');
415        $response->setLastModified(new \DateTime('@' . $feed_updated_time));
416
417        if (!empty($this->user->data['is_bot']))
418        {
419            // Let reverse proxies know we detected a bot.
420            $response->headers->set('X-PHPBB-IS-BOT', 'yes');
421        }
422
423        return $response;
424    }
425
426    /**
427     * Check if feeds are enabled in the configuration.
428     *
429     * @throws http_exception If feeds are disabled.
430     *
431     * @return void
432     */
433    protected function check_enabled()
434    {
435        // Feeds are disabled, no need to continue
436        if (!$this->config['feed_enable'])
437        {
438            throw new http_exception(404, 'NO_FEED_ENABLED');
439        }
440    }
441
442    /**
443     * Throw and exception saying that the feed isn't available
444     *
445     * @throws http_exception
446     */
447    protected function send_unavailable()
448    {
449        throw new http_exception(404, 'FEATURE_NOT_AVAILABLE');
450    }
451}