1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22/** 23 * This controller is used by gtlc.js to update time selector date and time interval in user's profile. 24 */ 25class CControllerTimeSelectorUpdate extends CController { 26 27 /** 28 * @var CRangeTimeParser 29 */ 30 private $range_time_parser; 31 32 private $data = []; 33 34 public function init() { 35 $this->disableSIDvalidation(); 36 37 $this->range_time_parser = new CRangeTimeParser(); 38 } 39 40 protected function checkInput() { 41 $profiles = ['web.dashbrd.filter', 'web.screens.filter', 'web.graphs.filter', 'web.httpdetails.filter', 42 'web.problem.filter', 'web.auditlogs.filter', 'web.slides.filter', 'web.auditacts.filter', 43 'web.item.graph.filter', 'web.toptriggers.filter', 'web.avail_report.filter' 44 ]; 45 46 $fields = [ 47 'method' => 'required|in increment,zoomout,decrement,rangechange,rangeoffset', 48 'idx' => 'required|in '.implode(',', $profiles), 49 'idx2' => 'required|id', 50 'from' => 'required|string', 51 'to' => 'required|string', 52 'from_offset' => 'int32|ge 0', 53 'to_offset' => 'int32|ge 0' 54 ]; 55 56 $ret = $this->validateInput($fields); 57 58 if (!$ret) { 59 /* 60 * This block executes if, for example, a missing profile is given. Since this is an AJAX request, it should 61 * throw a JS alert() with current message in timeSelectorEventHandler() in gtlc.js. 62 */ 63 64 global $ZBX_MESSAGES; 65 66 $this->setResponse(new CControllerResponseData([ 67 'main_block' => CJs::encodeJson(['error' => $ZBX_MESSAGES[0]['message']]) 68 ])); 69 70 return $ret; 71 } 72 73 $ret = $this->validateInputDateRange(); 74 75 if ($this->getInput('method') === 'rangeoffset' && (!$this->hasInput('from_offset') 76 || !$this->hasInput('to_offset'))) { 77 $ret = false; 78 } 79 80 if (!$ret) { 81 $this->setResponse(new CControllerResponseData(['main_block' => CJs::encodeJson($this->data)])); 82 } 83 84 return $ret; 85 } 86 87 protected function checkPermissions() { 88 return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); 89 } 90 91 protected function doAction() { 92 $method = $this->getInput('method'); 93 $date = new DateTime(); 94 $value = []; 95 $date_type = []; 96 $ts = []; 97 $ts['now'] = time(); 98 99 foreach (['from', 'to'] as $field) { 100 $value[$field] = $this->getInput($field); 101 $this->range_time_parser->parse($value[$field]); 102 $date_type[$field] = $this->range_time_parser->getTimeType(); 103 $ts[$field] = $this->range_time_parser->getDateTime($field === 'from')->getTimestamp(); 104 } 105 106 $period = $ts['to'] - $ts['from'] + 1; 107 108 switch ($method) { 109 case 'decrement': 110 $offset = $period; 111 112 if ($ts['from'] - $offset < 0) { 113 $offset = $ts['from']; 114 } 115 116 $ts['from'] -= $offset; 117 $ts['to'] -= $offset; 118 119 $value['from'] = $date->setTimestamp($ts['from'])->format(ZBX_FULL_DATE_TIME); 120 $value['to'] = $date->setTimestamp($ts['to'])->format(ZBX_FULL_DATE_TIME); 121 break; 122 123 case 'increment': 124 $offset = $period; 125 126 if ($ts['to'] + $offset > $ts['now']) { 127 $offset = $ts['now'] - $ts['to']; 128 } 129 130 $ts['from'] += $offset; 131 $ts['to'] += $offset; 132 133 $value['from'] = $date->setTimestamp($ts['from'])->format(ZBX_FULL_DATE_TIME); 134 $value['to'] = $date->setTimestamp($ts['to'])->format(ZBX_FULL_DATE_TIME); 135 break; 136 137 case 'zoomout': 138 $right_offset = (int) ($period / 2); 139 if ($ts['to'] + $right_offset > $ts['now']) { 140 $right_offset = $ts['now'] - $ts['to']; 141 } 142 $left_offset = $period - $right_offset; 143 if ($ts['from'] - $left_offset < 0) { 144 $left_offset = $ts['from']; 145 } 146 147 $ts['from'] -= $left_offset; 148 $ts['to'] += $right_offset; 149 150 if ($ts['to'] - $ts['from'] + 1 > ZBX_MAX_PERIOD) { 151 $ts['from'] = $ts['to'] - ZBX_MAX_PERIOD + 1; 152 } 153 154 $value['from'] = $date->setTimestamp($ts['from'])->format(ZBX_FULL_DATE_TIME); 155 $value['to'] = $date->setTimestamp($ts['to'])->format(ZBX_FULL_DATE_TIME); 156 break; 157 158 case 'rangeoffset': 159 $from_offset = $this->getInput('from_offset'); 160 $to_offset = $this->getInput('to_offset'); 161 162 if ($from_offset > 0) { 163 $ts['from'] += $from_offset; 164 $value['from'] = $date->setTimestamp($ts['from'])->format(ZBX_FULL_DATE_TIME); 165 } 166 167 if ($to_offset > 0) { 168 $ts['to'] -= $to_offset; 169 $value['to'] = $date->setTimestamp($ts['to'])->format(ZBX_FULL_DATE_TIME); 170 } 171 break; 172 173 case 'rangechange': 174 // Format only absolute date according ZBX_FULL_DATE_TIME string. 175 foreach (['from', 'to'] as $field) { 176 if ($date_type[$field] === CRangeTimeParser::ZBX_TIME_ABSOLUTE) { 177 $value[$field] = $date->setTimestamp($ts[$field])->format(ZBX_FULL_DATE_TIME); 178 } 179 } 180 break; 181 } 182 183 updateTimeSelectorPeriod([ 184 'profileIdx' => $this->getInput('idx'), 185 'profileIdx2' => $this->getInput('idx2'), 186 'from' => $value['from'], 187 'to' => $value['to'] 188 ]); 189 190 $this->setResponse(new CControllerResponseData(['main_block' => CJs::encodeJson([ 191 'label' => relativeDateToText($value['from'], $value['to']), 192 'from' => $value['from'], 193 'from_ts' => $ts['from'], 194 'from_date' => $date->setTimestamp($ts['from'])->format(ZBX_FULL_DATE_TIME), 195 'to' => $value['to'], 196 'to_ts' => $ts['to'], 197 'to_date' => $date->setTimestamp($ts['to'])->format(ZBX_FULL_DATE_TIME), 198 'can_zoomout' => ($ts['to'] - $ts['from'] + 1 < ZBX_MAX_PERIOD), 199 'can_decrement' => ($ts['from'] > 0), 200 'can_increment' => ($ts['to'] < $ts['now'] - ZBX_MIN_PERIOD) 201 ])])); 202 } 203 204 /** 205 * Validate input 'from' and 'to' arguments. Returns true on success. 206 * 207 * @return bool 208 */ 209 protected function validateInputDateRange() { 210 $this->data['error'] = []; 211 $ts = []; 212 213 foreach (['from', 'to'] as $field) { 214 $value = $this->getInput($field); 215 216 if ($this->range_time_parser->parse($value) !== CParser::PARSE_SUCCESS) { 217 $this->data['error'][$field] = _('Invalid date.'); 218 } 219 else { 220 $ts[$field] = $this->range_time_parser->getDateTime($field === 'from')->getTimestamp(); 221 } 222 } 223 224 if ($this->data['error']) { 225 return false; 226 } 227 228 if ($this->getInput('method') === 'rangeoffset') { 229 $ts['from'] += $this->getInput('from_offset'); 230 $ts['to'] -= $this->getInput('to_offset'); 231 } 232 233 $period = $ts['to'] - $ts['from'] + 1; 234 235 if ($period < ZBX_MIN_PERIOD) { 236 $this->data['error']['from'] = _n('Minimum time period to display is %1$s minute.', 237 'Minimum time period to display is %1$s minutes.', (int) (ZBX_MIN_PERIOD / SEC_PER_MIN) 238 ); 239 } 240 elseif ($period > ZBX_MAX_PERIOD) { 241 $this->data['error']['from'] = _n('Maximum time period to display is %1$s day.', 242 'Maximum time period to display is %1$s days.', (int) (ZBX_MAX_PERIOD / SEC_PER_DAY) 243 ); 244 } 245 246 return !$this->data['error']; 247 } 248} 249