1<?php
2/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
3
4namespace Icinga\Module\Monitoring;
5
6use Icinga\Exception\ConfigurationError;
7use Icinga\Exception\QueryException;
8use Icinga\Data\Filter\Filter;
9use Icinga\Data\Filterable;
10use Icinga\File\Csv;
11use Icinga\Util\Json;
12use Icinga\Web\Controller as IcingaWebController;
13use Icinga\Web\Url;
14
15/**
16 * Base class for all monitoring action controller
17 */
18class Controller extends IcingaWebController
19{
20    /**
21     * The backend used for this controller
22     *
23     * @var Backend
24     */
25    protected $backend;
26
27    protected function moduleInit()
28    {
29        $this->backend = Backend::createBackend($this->_getParam('backend'));
30        $this->view->url = Url::fromRequest();
31    }
32
33    protected function handleFormatRequest($query)
34    {
35        $desiredContentType = $this->getRequest()->getHeader('Accept');
36        if ($desiredContentType === 'application/json') {
37            $desiredFormat = 'json';
38        } elseif ($desiredContentType === 'text/csv') {
39            $desiredFormat = 'csv';
40        } else {
41            $desiredFormat = strtolower($this->params->get('format', 'html'));
42        }
43
44        if ($desiredFormat !== 'html' && ! $this->params->has('limit')) {
45            $query->limit();  // Resets any default limit and offset
46        }
47
48        switch ($desiredFormat) {
49            case 'sql':
50                echo '<pre>'
51                    . htmlspecialchars(wordwrap($query->dump()))
52                    . '</pre>';
53                exit;
54            case 'json':
55                $response = $this->getResponse();
56                $response
57                    ->setHeader('Content-Type', 'application/json')
58                    ->setHeader('Cache-Control', 'no-store')
59                    ->setHeader(
60                        'Content-Disposition',
61                        'inline; filename=' . $this->getRequest()->getActionName() . '.json'
62                    )
63                    ->appendBody(Json::sanitize($query->fetchAll()))
64                    ->sendResponse();
65                exit;
66            case 'csv':
67                $response = $this->getResponse();
68                $response
69                    ->setHeader('Content-Type', 'text/csv')
70                    ->setHeader('Cache-Control', 'no-store')
71                    ->setHeader(
72                        'Content-Disposition',
73                        'attachment; filename=' . $this->getRequest()->getActionName() . '.csv'
74                    )
75                    ->appendBody((string) Csv::fromQuery($query))
76                    ->sendResponse();
77                exit;
78        }
79    }
80
81    /**
82     * Apply a restriction of the authenticated on the given filterable
83     *
84     * @param   string      $name       Name of the restriction
85     * @param   Filterable  $filterable Filterable to restrict
86     *
87     * @return  Filterable  The filterable having the restriction applied
88     */
89    protected function applyRestriction($name, Filterable $filterable)
90    {
91        $filterable->applyFilter($this->getRestriction($name));
92        return $filterable;
93    }
94
95    /**
96     * Get a restriction of the authenticated
97     *
98     * @param   string $name        Name of the restriction
99     *
100     * @return  Filter              Filter object
101     * @throws  ConfigurationError  If the restriction contains invalid filter columns
102     */
103    protected function getRestriction($name)
104    {
105        $restriction = Filter::matchAny();
106        $restriction->setAllowedFilterColumns(array(
107            'host_name',
108            'hostgroup_name',
109            'instance_name',
110            'service_description',
111            'servicegroup_name',
112            function ($c) {
113                return preg_match('/^_(?:host|service)_/i', $c);
114            }
115        ));
116        foreach ($this->getRestrictions($name) as $filter) {
117            if ($filter === '*') {
118                return Filter::matchAll();
119            }
120            try {
121                $restriction->addFilter(Filter::fromQueryString($filter));
122            } catch (QueryException $e) {
123                throw new ConfigurationError(
124                    $this->translate(
125                        'Cannot apply restriction %s using the filter %s. You can only use the following columns: %s'
126                    ),
127                    $name,
128                    $filter,
129                    implode(', ', array(
130                        'instance_name',
131                        'host_name',
132                        'hostgroup_name',
133                        'service_description',
134                        'servicegroup_name',
135                        '_(host|service)_<customvar-name>'
136                    )),
137                    $e
138                );
139            }
140        }
141
142        if ($restriction->isEmpty()) {
143            return Filter::matchAll();
144        }
145
146        return $restriction;
147    }
148}
149