Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 97
0.00% covered (danger)
0.00%
0 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
feed
0.00% covered (danger)
0.00%
0 / 97
0.00% covered (danger)
0.00%
0 / 12
2352
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 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 news
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 topics
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 topics_new
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 topics_active
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 forum
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 topic
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 overall
0.00% covered (danger)
0.00%
0 / 3
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
 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        if (!$this->config['feed_overall_forums'])
138        {
139            $this->send_unavailable();
140        }
141
142        return $this->send_feed($this->container->get('feed.forums'));
143    }
144
145    /**
146     * Controller for /feed/news route
147     *
148     * @return Response
149     *
150     * @throws http_exception when the feed is disabled
151     */
152    public function news()
153    {
154        // Get at least one news forum
155        $sql = 'SELECT forum_id
156                    FROM ' . FORUMS_TABLE . '
157                    WHERE ' . $this->db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0');
158        $result = $this->db->sql_query_limit($sql, 1, 0, 600);
159        $s_feed_news = (int) $this->db->sql_fetchfield('forum_id');
160        $this->db->sql_freeresult($result);
161
162        if (!$s_feed_news)
163        {
164            $this->send_unavailable();
165        }
166
167        return $this->send_feed($this->container->get('feed.news'));
168    }
169
170    /**
171     * Controller for /feed/topics route
172     *
173     * @return Response
174     *
175     * @throws http_exception when the feed is disabled
176     */
177    public function topics()
178    {
179        if (!$this->config['feed_topics_new'])
180        {
181            $this->send_unavailable();
182        }
183
184        return $this->send_feed($this->container->get('feed.topics'));
185    }
186
187    /**
188     * Controller for /feed/topics_new route
189     *
190     * @return Response
191     *
192     * @throws http_exception when the feed is disabled
193     */
194    public function topics_new()
195    {
196        return $this->topics();
197    }
198
199    /**
200     * Controller for /feed/topics_active route
201     *
202     * @return Response
203     *
204     * @throws http_exception when the feed is disabled
205     */
206    public function topics_active()
207    {
208        if (!$this->config['feed_topics_active'])
209        {
210            $this->send_unavailable();
211        }
212
213        return $this->send_feed($this->container->get('feed.topics_active'));
214    }
215
216    /**
217     * Controller for /feed/forum/{forum_id} route
218     *
219     * @param int $forum_id
220     *
221     * @return Response
222     *
223     * @throws http_exception when the feed is disabled
224     */
225    public function forum($forum_id)
226    {
227        if (!$this->config['feed_forum'])
228        {
229            $this->send_unavailable();
230        }
231
232        return $this->send_feed($this->container->get('feed.forum')->set_forum_id($forum_id));
233    }
234
235    /**
236     * Controller for /feed/topic/{topic_id} route
237     *
238     * @param int $topic_id
239     *
240     * @return Response
241     *
242     * @throws http_exception when the feed is disabled
243     */
244    public function topic($topic_id)
245    {
246        if (!$this->config['feed_topic'])
247        {
248            $this->send_unavailable();
249        }
250
251        return $this->send_feed($this->container->get('feed.topic')->set_topic_id($topic_id));
252    }
253
254    /**
255     * Controller for /feed/{mode] route
256     *
257     * @return Response
258     *
259     * @throws http_exception when the feed is disabled
260     */
261    public function overall()
262    {
263        if (!$this->config['feed_overall'])
264        {
265            $this->send_unavailable();
266        }
267
268        return $this->send_feed($this->container->get('feed.overall'));
269    }
270
271    /**
272     * Display a given feed
273     *
274     * @param feed_interface $feed
275     *
276     * @return Response
277     */
278    protected function send_feed(feed_interface $feed)
279    {
280        try
281        {
282            return $this->send_feed_do($feed);
283        }
284        catch (feed_unavailable_exception $e)
285        {
286            throw new http_exception(Response::HTTP_NOT_FOUND, $e->getMessage(), $e->get_parameters(), $e);
287        }
288        catch (unauthorized_exception $e)
289        {
290            throw new http_exception(Response::HTTP_FORBIDDEN, $e->getMessage(), $e->get_parameters(), $e);
291        }
292    }
293
294    /**
295     * Really send the feed
296     *
297     * @param feed_interface $feed
298     *
299     * @return Response
300     *
301     * @throws \phpbb\feed\exception\feed_exception
302     */
303    protected function send_feed_do(feed_interface $feed)
304    {
305        $feed_updated_time = 0;
306        $item_vars = array();
307        $this->language->add_lang('viewtopic');
308
309        $board_url = $this->feed_helper->get_board_url();
310
311        // Open Feed
312        $feed->open();
313
314        // Iterate through items
315        while ($row = $feed->get_item())
316        {
317            /**
318             * Event to modify the feed row
319             *
320             * @event core.feed_modify_feed_row
321             * @var    feed_interface feed Feed instance
322             * @var    array    row            Array with feed data
323             *
324             * @since 3.1.10-RC1
325             * @changed 3.3.0 Replace forum_id, mode, topic_id with feed instance
326             */
327            $vars = array('feed', 'row');
328            extract($this->phpbb_dispatcher->trigger_event('core.feed_modify_feed_row', compact($vars)));
329
330            // BBCode options to correctly disable urls, smilies, bbcode...
331            if ($feed->get('options') === null)
332            {
333                // Allow all combinations
334                $options = 7;
335
336                if ($feed->get('enable_bbcode') !== null && $feed->get('enable_smilies') !== null && $feed->get('enable_magic_url') !== null)
337                {
338                    $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);
339                }
340            }
341            else
342            {
343                $options = $row[$feed->get('options')];
344            }
345
346            $title = (isset($row[$feed->get('title')]) && $row[$feed->get('title')] !== '') ? $row[$feed->get('title')] : ((isset($row[$feed->get('title2')])) ? $row[$feed->get('title2')] : '');
347
348            $published = ($feed->get('published') !== null) ? (int) $row[$feed->get('published')] : 0;
349            $updated = ($feed->get('updated') !== null) ? (int) $row[$feed->get('updated')] : 0;
350
351            $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;
352
353            $item_row = array(
354                'author'        => ($feed->get('creator') !== null) ? $row[$feed->get('creator')] : '',
355                'published'        => ($published > 0) ? $this->feed_helper->format_date($published) : '',
356                'updated'        => ($updated > 0) ? $this->feed_helper->format_date($updated) : '',
357                'link'            => '',
358                'title'            => censor_text($title),
359                'category'        => ($this->config['feed_item_statistics'] && !empty($row['forum_id'])) ? $board_url . '/viewforum.' . $this->php_ext . '?f=' . $row['forum_id'] : '',
360                'category_name'    => ($this->config['feed_item_statistics'] && isset($row['forum_name'])) ? $row['forum_name'] : '',
361                '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()))),
362                'statistics'    => '',
363            );
364
365            // Adjust items, fill link, etc.
366            $feed->adjust_item($item_row, $row);
367
368            $item_vars[] = $item_row;
369
370            $feed_updated_time = max($feed_updated_time, $published, $updated);
371        }
372
373        // If we do not have any items at all, sending the current time is better than sending no time.
374        if (!$feed_updated_time)
375        {
376            $feed_updated_time = time();
377        }
378
379        $feed->close();
380
381        $content = $this->template->render('feed.xml.twig', array(
382            // Some default assignments
383            // FEED_IMAGE is not used (atom)
384            'FEED_IMAGE'            => '',
385            'SELF_LINK'                => $this->controller_helper->route($this->request->attributes->get('_route'), $this->request->attributes->get('_route_params'), true, '', UrlGeneratorInterface::ABSOLUTE_URL),
386            'FEED_LINK'                => $board_url . '/index.' . $this->php_ext,
387            'FEED_TITLE'            => $this->config['sitename'],
388            'FEED_SUBTITLE'            => $this->config['site_desc'],
389            'FEED_UPDATED'            => $this->feed_helper->format_date($feed_updated_time),
390            'FEED_LANG'                => $this->language->lang('USER_LANG'),
391            'FEED_AUTHOR'            => $this->config['sitename'],
392
393            // Feed entries
394            'FEED_ROWS'                => $item_vars,
395        ));
396
397        $response = new Response($content);
398        $response->headers->set('Content-Type', 'application/atom+xml; charset=UTF-8');
399        $response->setLastModified(new \DateTime('@' . $feed_updated_time));
400
401        if (!empty($this->user->data['is_bot']))
402        {
403            // Let reverse proxies know we detected a bot.
404            $response->headers->set('X-PHPBB-IS-BOT', 'yes');
405        }
406
407        return $response;
408    }
409
410    /**
411     * Throw and exception saying that the feed isn't available
412     *
413     * @throws http_exception
414     */
415    protected function send_unavailable()
416    {
417        throw new http_exception(404, 'FEATURE_NOT_AVAILABLE');
418    }
419}