WecomCenterSave.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <?php declare(strict_types = 0);
  2. /*
  3. ** WeCom Center - POST controller. Dispatches actions and redirects back.
  4. */
  5. namespace Modules\WecomCenter\Actions;
  6. use CController;
  7. use CControllerResponseRedirect;
  8. use CUrl;
  9. use CWebUser;
  10. use Exception;
  11. use Modules\WecomCenter\Lib\Helper;
  12. use Modules\WecomCenter\Lib\I18n;
  13. class WecomCenterSave extends CController {
  14. protected function init() {
  15. $this->disableCsrfValidation();
  16. }
  17. protected function checkInput() {
  18. return true;
  19. }
  20. protected function checkPermissions() {
  21. return CWebUser::getType() == USER_TYPE_SUPER_ADMIN;
  22. }
  23. protected function doAction() {
  24. $mediatypeid = (string) ($_REQUEST['mediatypeid'] ?? '');
  25. try {
  26. // Strategy apply buttons are submitted as name="apply_strategy" value=<preset>.
  27. if (isset($_REQUEST['apply_strategy'])) {
  28. $this->applyStrategy($mediatypeid, (string) $_REQUEST['apply_strategy']);
  29. }
  30. else {
  31. $op = (string) ($_REQUEST['op'] ?? '');
  32. switch ($op) {
  33. case 'save_alert': $this->saveAlert($mediatypeid); break;
  34. case 'save_triggers': $this->saveTriggers(); break;
  35. case 'save_class_sev': $this->saveClassSeverity(); break;
  36. case 'save_robot': $this->saveRobot($mediatypeid); break;
  37. case 'test_robot': $this->testRobot($mediatypeid); break;
  38. case 'import_template': $this->importTemplate(); break;
  39. case 'save_map': $this->saveMap(); break;
  40. case 'apply_switch': $this->applySwitch(); break;
  41. case 'init_env': $this->initEnv(); break;
  42. default: error(I18n::t('msg.unknown_op'));
  43. }
  44. }
  45. }
  46. catch (Exception $e) {
  47. error($e->getMessage());
  48. }
  49. $url = (new CUrl('zabbix.php'))->setArgument('action', 'wecom.center.view');
  50. if ($mediatypeid !== '') {
  51. $url->setArgument('mediatypeid', $mediatypeid);
  52. }
  53. $tab = (string) ($_REQUEST['tab'] ?? '');
  54. if (in_array($tab, ['alert', 'opt', 'maint'], true)) {
  55. $url->setArgument('tab', $tab);
  56. if ($tab === 'maint') {
  57. $ts = (string) ($_REQUEST['trig_search'] ?? '');
  58. if ($ts !== '') {
  59. $url->setArgument('trig_search', $ts);
  60. }
  61. }
  62. }
  63. $this->setResponse(new CControllerResponseRedirect($url));
  64. }
  65. private function applyStrategy(string $mediatypeid, string $key): void {
  66. if (!isset(Helper::STRATEGY_PRESETS[$key])) {
  67. throw new Exception(I18n::t('msg.bad_scheme'));
  68. }
  69. $tid = Helper::templateHostid();
  70. if ($tid === null) {
  71. throw new Exception(I18n::t('msg.no_template_host'));
  72. }
  73. $preset = Helper::STRATEGY_PRESETS[$key];
  74. // 1) threshold on the media (global "how severe still notifies")
  75. if ($mediatypeid !== '') {
  76. $user = Helper::ensureRobotUser('wecomrobot');
  77. $mask = Helper::severityMaskFromMin((int) $preset['min']);
  78. Helper::applyMedia($user['userid'], $mediatypeid, $mask, 0);
  79. }
  80. // 2) classify + write severities
  81. $res = Helper::applyStrategy($tid, $preset['targets']);
  82. Helper::saveStrategyKey($key);
  83. info(I18n::t('msg.strategy_applied', [
  84. I18n::t($preset['label']),
  85. $res['trigger'],
  86. $res['prototype'],
  87. $res['discovered']
  88. ]));
  89. }
  90. private function saveAlert(string $mediatypeid): void {
  91. $active = isset($_REQUEST['enabled']) ? 0 : 1; // media: 0=enabled, 1=disabled
  92. $indices = [];
  93. for ($i = 1; $i <= 6; $i++) {
  94. if (isset($_REQUEST['sev_'.$i])) {
  95. $indices[] = $i;
  96. }
  97. }
  98. $mask = Helper::severityMask($indices);
  99. if ($mask === 0 && $active === 0) {
  100. $mask = 2;
  101. }
  102. $user = Helper::ensureRobotUser('wecomrobot');
  103. Helper::applyMedia($user['userid'], $mediatypeid, $mask, $active);
  104. info(I18n::t('msg.saved'));
  105. }
  106. private function saveRobot(string $mediatypeid): void {
  107. $url = trim((string) ($_REQUEST['webhook_url'] ?? ''));
  108. if ($url !== '') {
  109. Helper::setWebhookKey($url);
  110. }
  111. $user = Helper::ensureRobotUser('wecomrobot');
  112. $cur = Helper::currentMedia($user, $mediatypeid);
  113. $mask = $cur['severity'] ?? 48;
  114. $active = $cur['active'] ?? 0;
  115. Helper::applyMedia($user['userid'], $mediatypeid, $mask, $active);
  116. info(I18n::t('msg.robot_saved'));
  117. }
  118. private function testRobot(string $mediatypeid): void {
  119. $mt = Helper::getMediatype($mediatypeid);
  120. if (!$mt) {
  121. throw new Exception(I18n::t('msg.no_mediatype'));
  122. }
  123. $url = Helper::webhookUrl($mt);
  124. if ($url === '') {
  125. throw new Exception(I18n::t('msg.no_url'));
  126. }
  127. $text = '['.I18n::t('page.title').'] Test OK - '.date('Y-m-d H:i:s');
  128. $res = Helper::testWebhook($url, $text);
  129. $body = (string) $res['body'];
  130. $ok = (strpos($body, '"errcode":0') !== false) || (strpos($body, '"errcode": 0') !== false);
  131. if ($ok) {
  132. info(I18n::t('msg.tested'));
  133. }
  134. else {
  135. error(I18n::t('msg.test_failed', [$res['status'], $body]));
  136. }
  137. }
  138. private function importTemplate(): void {
  139. $file = (string) ($_REQUEST['template_file'] ?? '');
  140. if ($file === '') {
  141. throw new Exception(I18n::t('msg.no_template'));
  142. }
  143. $module_dir = dirname(__DIR__);
  144. $res = Helper::importTemplate($module_dir, $file);
  145. $n = isset($res['templates']) && is_array($res['templates']) ? count($res['templates']) : 0;
  146. info(I18n::t('msg.imported', [$n]));
  147. }
  148. private function saveTriggers(): void {
  149. $ids = (string) ($_REQUEST['trig_ids'] ?? '');
  150. $ids = array_filter(array_map('trim', explode(',', $ids)));
  151. if (!$ids) {
  152. throw new Exception(I18n::t('msg.no_triggers'));
  153. }
  154. $changed = 0;
  155. $sev_changed = 0;
  156. foreach ($ids as $id) {
  157. $id = (int) $id;
  158. if ($id <= 0) {
  159. continue;
  160. }
  161. $status = isset($_REQUEST['trig_'.$id]) ? 0 : 1; // checkbox = enabled
  162. $priority = null;
  163. if (isset($_REQUEST['pse_'.$id]) && $_REQUEST['pse_'.$id] !== '') {
  164. $priority = (int) $_REQUEST['pse_'.$id];
  165. $sev_changed++;
  166. }
  167. Helper::setTriggerState((string) $id, $priority, $status);
  168. $changed++;
  169. }
  170. info(I18n::t('msg.triggers_saved', [$changed]));
  171. }
  172. private function saveClassSeverity(): void {
  173. $ck = (string) ($_REQUEST['class_key'] ?? '');
  174. $p = (int) ($_REQUEST['class_priority'] ?? -1);
  175. if ($ck === '' || $p < 0 || $p > 5) {
  176. throw new Exception(I18n::t('msg.bad_class_sev'));
  177. }
  178. $r = Helper::setClassSeverity($ck, $p);
  179. info(I18n::t('msg.class_sev_saved', [$r['trigger'] + $r['prototype'], $r['discovered']]));
  180. }
  181. private function saveMap(): void {
  182. $hostid = (string) ($_REQUEST['hostid'] ?? '');
  183. $lat = trim((string) ($_REQUEST['lat'] ?? ''));
  184. $lon = trim((string) ($_REQUEST['lon'] ?? ''));
  185. if ($hostid === '') {
  186. throw new Exception(I18n::t('msg.no_host'));
  187. }
  188. Helper::setHostLocation($hostid, $lat, $lon);
  189. info(I18n::t('msg.map_saved'));
  190. }
  191. private function applySwitch(): void {
  192. $src = (string) ($_REQUEST['switch_src'] ?? '');
  193. $dst = (string) ($_REQUEST['switch_dst'] ?? '');
  194. if ($src === '' || $dst === '') {
  195. throw new Exception(I18n::t('msg.need_both'));
  196. }
  197. if ($src === $dst) {
  198. throw new Exception(I18n::t('msg.same_tpl'));
  199. }
  200. $n = Helper::switchApply($src, $dst);
  201. info(I18n::t('msg.switch_applied', [$n]));
  202. }
  203. private function initEnv(): void {
  204. $key = trim((string) ($_REQUEST['key'] ?? $_REQUEST['webhook_url'] ?? ''));
  205. $proto = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
  206. $host = (string) ($_SERVER['HTTP_HOST'] ?? '');
  207. $zbxUrl = $host !== '' ? $proto.'://'.$host : '';
  208. $r = Helper::initializeEnvironment($key, $zbxUrl);
  209. $parts = [];
  210. $parts[] = $r['created_mediatype'] ? I18n::t('msg.init_mediatype_new') : I18n::t('msg.init_mediatype_ok');
  211. $parts[] = $r['created_user'] ? I18n::t('msg.init_user_new') : I18n::t('msg.init_user_ok');
  212. $parts[] = $r['created_action'] ? I18n::t('msg.init_action_new') : I18n::t('msg.init_action_ok');
  213. if ($r['key_set']) {
  214. $parts[] = I18n::t('msg.init_key_set');
  215. }
  216. info(I18n::t('msg.init_done', [implode(' · ', $parts)]));
  217. }
  218. }