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
22include('include/views/js/administration.users.edit.js.php');
23
24if ($data['is_profile']) {
25	$userWidget = ($data['name'] !== '' || $data['surname'] !== '')
26		? (new CWidget())->setTitle(_('User profile').NAME_DELIMITER.$data['name'].' '.$data['surname'])
27		: (new CWidget())->setTitle(_('User profile').NAME_DELIMITER.$data['alias']);
28}
29else {
30	$userWidget = (new CWidget())->setTitle(_('Users'));
31}
32
33// create form
34$userForm = (new CForm())
35	->setName('userForm')
36	->setAttribute('aria-labeledby', ZBX_STYLE_PAGE_TITLE)
37	->addVar('form', $data['form']);
38
39if ($data['userid'] != 0) {
40	$userForm->addVar('userid', $data['userid']);
41}
42
43/*
44 * User tab
45 */
46$userFormList = new CFormList('userFormList');
47$form_autofocus = false;
48
49if (!$data['is_profile']) {
50	$userFormList->addRow(
51		(new CLabel(_('Alias'), 'alias'))->setAsteriskMark(),
52		(new CTextBox('alias', $data['alias']))
53			->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
54			->setAriaRequired()
55			->setAttribute('autofocus', 'autofocus')
56			->setAttribute('maxlength', DB::getFieldLength('users', 'alias'))
57	);
58	$form_autofocus = true;
59	$userFormList->addRow(_x('Name', 'user first name'),
60		(new CTextBox('name', $data['name']))
61			->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
62			->setAttribute('maxlength', DB::getFieldLength('users', 'name'))
63	);
64	$userFormList->addRow(_('Surname'),
65		(new CTextBox('surname', $data['surname']))
66			->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
67			->setAttribute('maxlength', DB::getFieldLength('users', 'surname'))
68	);
69}
70
71// append user groups to form list
72if (!$data['is_profile']) {
73	$user_groups = [];
74
75	foreach ($data['groups'] as $group) {
76		$user_groups[] = CArrayHelper::renameKeys($group, ['usrgrpid' => 'id']);
77	}
78
79	$userFormList->addRow(
80		(new CLabel(_('Groups'), 'user_groups__ms'))->setAsteriskMark(),
81		(new CMultiSelect([
82			'name' => 'user_groups[]',
83			'object_name' => 'usersGroups',
84			'data' => $user_groups,
85			'popup' => [
86				'parameters' => [
87					'srctbl' => 'usrgrp',
88					'srcfld1' => 'usrgrpid',
89					'dstfrm' => $userForm->getName(),
90					'dstfld1' => 'user_groups_'
91				]
92			]
93		]))
94			->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
95			->setAriaRequired()
96	);
97}
98
99// append password to form list
100if ($data['userid'] == 0 || $data['change_password']) {
101	$userForm->disablePasswordAutofill();
102
103	$password1 = (new CPassBox('password1', $data['password1']))
104		->setWidth(ZBX_TEXTAREA_SMALL_WIDTH)
105		->setAriaRequired();
106
107	if (!$form_autofocus) {
108		$form_autofocus = true;
109		$password1->setAttribute('autofocus', 'autofocus');
110	}
111
112	$userFormList
113		->addRow((new CLabel(_('Password'), 'password1'))->setAsteriskMark(), [
114			// Hidden dummy login field for protection against chrome error when password autocomplete.
115			(new CInput('text', null, null))
116				->setAttribute('tabindex', '-1')
117				->addStyle('position: absolute; left: -100vw;'),
118			$password1
119		])
120		->addRow((new CLabel(_('Password (once again)'), 'password2'))->setAsteriskMark(),
121			(new CPassBox('password2', $data['password2']))
122				->setWidth(ZBX_TEXTAREA_SMALL_WIDTH)
123				->setAriaRequired()
124		)
125		->addRow('', _('Password is not mandatory for non internal authentication type.'));
126
127	if ($data['change_password']) {
128		$userForm->addVar('change_password', $data['change_password']);
129	}
130}
131else {
132	$passwdButton = (new CSimpleButton(_('Change password')))
133		->onClick('javascript: submitFormWithParam("'.$userForm->getName().'", "change_password", "1");')
134		->addClass(ZBX_STYLE_BTN_GREY);
135	if ($data['alias'] == ZBX_GUEST_USER) {
136		$passwdButton->setAttribute('disabled', 'disabled');
137	}
138
139	if (!$form_autofocus) {
140		$form_autofocus = true;
141		$passwdButton->setAttribute('autofocus', 'autofocus');
142	}
143
144	$userFormList->addRow(_('Password'), $passwdButton);
145}
146
147// append languages to form list
148$languageComboBox = new CComboBox('lang', $data['lang']);
149
150$allLocalesAvailable = true;
151foreach (getLocales() as $localeId => $locale) {
152	if ($locale['display']) {
153		// checking if this locale exists in the system. The only way of doing it is to try and set one
154		// trying to set only the LC_MONETARY locale to avoid changing LC_NUMERIC
155		$localeExists = ($localeId === 'en_GB' || setlocale(LC_MONETARY , zbx_locale_variants($localeId)));
156
157		$languageComboBox->addItem(
158			$localeId,
159			$locale['name'],
160			($localeId == $data['lang']) ? true : null,
161			$localeExists
162		);
163
164		$allLocalesAvailable &= $localeExists;
165	}
166}
167
168// restoring original locale
169setlocale(LC_MONETARY, zbx_locale_variants(CWebUser::$data['lang']));
170
171$languageError = '';
172if (!function_exists('bindtextdomain')) {
173	$languageError = 'Translations are unavailable because the PHP gettext module is missing.';
174	$languageComboBox->setAttribute('disabled', 'disabled');
175}
176elseif (!$allLocalesAvailable) {
177	$languageError = _('You are not able to choose some of the languages, because locales for them are not installed on the web server.');
178}
179
180if (!$form_autofocus && $languageComboBox->getAttribute('disabled') === null) {
181	$languageComboBox->setAttribute('autofocus', 'autofocus');
182	$form_autofocus = true;
183}
184
185$userFormList->addRow(
186	_('Language'),
187	$languageError
188		? [$languageComboBox, SPACE, (new CSpan($languageError))->addClass('red')->addClass('wrap')]
189		: $languageComboBox
190);
191
192// append themes to form list
193$themes = array_merge([THEME_DEFAULT => _('System default')], Z::getThemes());
194$themes_combobox = new CComboBox('theme', $data['theme'], null, $themes);
195
196if (!$form_autofocus) {
197	$themes_combobox->setAttribute('autofocus', 'autofocus');
198	$form_autofocus = true;
199}
200
201$userFormList->addRow(_('Theme'), $themes_combobox);
202
203// append auto-login & auto-logout to form list
204$autologoutCheckBox = (new CCheckBox('autologout_visible'))->setChecked($data['autologout_visible']);
205if ($data['autologout_visible']) {
206	$autologoutTextBox = (new CTextBox('autologout', $data['autologout']))->setWidth(ZBX_TEXTAREA_TINY_WIDTH);
207}
208else {
209	$autologoutTextBox = (new CTextBox('autologout', DB::getDefault('users', 'autologout')))
210		->setWidth(ZBX_TEXTAREA_TINY_WIDTH)
211		->setAttribute('disabled', 'disabled');
212}
213
214if ($data['alias'] != ZBX_GUEST_USER) {
215	$userFormList->addRow(_('Auto-login'), (new CCheckBox('autologin'))->setChecked($data['autologin']));
216	$userFormList->addRow(_('Auto-logout'), [
217		$autologoutCheckBox,
218		(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
219		$autologoutTextBox
220	]);
221}
222
223$userFormList
224	->addRow((new CLabel(_('Refresh'), 'refresh'))->setAsteriskMark(),
225		(new CTextBox('refresh', $data['refresh']))
226			->setWidth(ZBX_TEXTAREA_TINY_WIDTH)
227			->setAriaRequired()
228	)
229	->addRow((new CLabel(_('Rows per page'), 'rows_per_page'))->setAsteriskMark(),
230		(new CNumericBox('rows_per_page', $data['rows_per_page'], 6))
231			->setWidth(ZBX_TEXTAREA_NUMERIC_STANDARD_WIDTH)
232			->setAriaRequired()
233	)
234	->addRow(_('URL (after login)'),
235		(new CTextBox('url', $data['url']))->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH)
236	);
237
238/*
239 * Media tab
240 */
241if (uint_in_array(CWebUser::$data['type'], [USER_TYPE_ZABBIX_ADMIN, USER_TYPE_SUPER_ADMIN])) {
242	$userMediaFormList = new CFormList('userMediaFormList');
243	$userForm->addVar('user_medias', $data['user_medias']);
244
245	$mediaTableInfo = (new CTable())
246		->setAttribute('style', 'width: 100%;')
247		->setHeader([_('Type'), _('Send to'), _('When active'), _('Use if severity'), ('Status'), _('Action')]);
248
249	foreach ($data['user_medias'] as $id => $media) {
250		if (!array_key_exists('active', $media) || !$media['active']) {
251			$status = (new CLink(_('Enabled'), '#'))
252				->addClass(ZBX_STYLE_LINK_ACTION)
253				->addClass(ZBX_STYLE_GREEN)
254				->onClick('return create_var("'.$userForm->getName().'","disable_media",'.$id.', true);');
255		}
256		else {
257			$status = (new CLink(_('Disabled'), '#'))
258				->addClass(ZBX_STYLE_LINK_ACTION)
259				->addClass(ZBX_STYLE_RED)
260				->onClick('return create_var("'.$userForm->getName().'","enable_media",'.$id.', true);');
261		}
262
263		$popup_options = [
264			'dstfrm' => $userForm->getName(),
265			'media' => $id,
266			'mediatypeid' => $media['mediatypeid'],
267			'period' => $media['period'],
268			'severity' => $media['severity'],
269			'active' => $media['active']
270		];
271
272		if ($media['mediatype'] == MEDIA_TYPE_EMAIL) {
273			foreach ($media['sendto'] as $email) {
274				$popup_options['sendto_emails'][] = $email;
275			}
276		}
277		else {
278			$popup_options['sendto'] = $media['sendto'];
279		}
280
281		$mediaSeverity = [];
282
283		for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) {
284			$severityName = getSeverityName($severity, $data['config']);
285			$severity_status_style = getSeverityStatusStyle($severity);
286
287			$mediaActive = ($media['severity'] & (1 << $severity));
288
289			$mediaSeverity[$severity] = (new CSpan(mb_substr($severityName, 0, 1)))
290				->setHint($severityName.' ('.($mediaActive ? _('on') : _('off')).')', '', false)
291				->addClass($mediaActive ? $severity_status_style : ZBX_STYLE_STATUS_DISABLED_BG);
292		}
293
294		if ($media['mediatype'] == MEDIA_TYPE_EMAIL) {
295			$media['sendto'] = implode(', ', $media['sendto']);
296		}
297
298		if (mb_strlen($media['sendto']) > 50) {
299			$media['sendto'] = (new CSpan(mb_substr($media['sendto'], 0, 50).'...'))->setHint($media['sendto']);
300		}
301
302		$mediaTableInfo->addRow(
303			(new CRow([
304				$media['description'],
305				$media['sendto'],
306				(new CDiv($media['period']))
307					->setAttribute('style', 'max-width: '.ZBX_TEXTAREA_STANDARD_WIDTH.'px;')
308					->addClass(ZBX_STYLE_OVERFLOW_ELLIPSIS),
309				(new CDiv($mediaSeverity))->addClass(ZBX_STYLE_STATUS_CONTAINER),
310				$status,
311				(new CCol(
312					new CHorList([
313						(new CButton(null, _('Edit')))
314							->addClass(ZBX_STYLE_BTN_LINK)
315							->onClick('return PopUp("popup.media",'.CJs::encodeJson($popup_options).', null, this);'),
316						(new CButton(null, _('Remove')))
317							->addClass(ZBX_STYLE_BTN_LINK)
318							->onClick('javascript: removeMedia('.$id.');')
319					])
320				))->addClass(ZBX_STYLE_NOWRAP)
321			]))->setId('user_medias_'.$id)
322		);
323	}
324
325	$userMediaFormList->addRow(_('Media'),
326		(new CDiv([
327			$mediaTableInfo,
328			(new CButton(null, _('Add')))
329				->onClick('return PopUp("popup.media",'.
330					CJs::encodeJson([
331						'dstfrm' => $userForm->getName()
332					]).', null, this);'
333				)
334				->addClass(ZBX_STYLE_BTN_LINK)
335		]))
336			->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR)
337			->setAttribute('style', 'min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;')
338	);
339}
340else {
341	$userMediaFormList = null;
342}
343
344/*
345 * Profile fields
346 */
347if ($data['is_profile']) {
348	$zbxSounds = getSounds();
349
350	$userMessagingFormList = new CFormList();
351	$userMessagingFormList->addRow(_('Frontend messaging'),
352		(new CCheckBox('messages[enabled]'))
353			->setChecked($data['messages']['enabled'] == 1)
354			->setUncheckedValue(0)
355	);
356	$userMessagingFormList->addRow(_('Message timeout'),
357		(new CTextBox('messages[timeout]', $data['messages']['timeout']))
358			->setWidth(ZBX_TEXTAREA_TINY_WIDTH),
359		'timeout_row'
360	);
361
362	$repeatSound = new CComboBox('messages[sounds.repeat]', $data['messages']['sounds.repeat'],
363		'if (IE) { submit() }',
364		[
365			1 => _('Once'),
366			10 => '10 '._('Seconds'),
367			-1 => _('Message timeout')
368		]
369	);
370	$userMessagingFormList->addRow(_('Play sound'), $repeatSound, 'repeat_row');
371
372	$soundList = new CComboBox('messages[sounds.recovery]', $data['messages']['sounds.recovery']);
373	foreach ($zbxSounds as $filename => $file) {
374		$soundList->addItem($file, $filename);
375	}
376
377	$triggersTable = (new CTable())
378		->addRow([
379			(new CCheckBox('messages[triggers.recovery]'))
380				->setLabel(_('Recovery'))
381				->setChecked($data['messages']['triggers.recovery'] == 1)
382				->setUncheckedValue(0),
383			[
384				$soundList,
385				(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
386				(new CButton('start', _('Play')))
387					->addClass(ZBX_STYLE_BTN_GREY)
388					->onClick("javascript: testUserSound('messages_sounds.recovery');")
389					->removeId(),
390				(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
391				(new CButton('stop', _('Stop')))
392					->addClass(ZBX_STYLE_BTN_GREY)
393					->onClick('javascript: AudioControl.stop();')
394					->removeId()
395			]
396		]);
397
398	$msgVisibility = ['1' => [
399		'messages[timeout]',
400		'messages[sounds.repeat]',
401		'messages[sounds.recovery]',
402		'messages[triggers.recovery]',
403		'timeout_row',
404		'repeat_row',
405		'triggers_row'
406	]];
407
408	// trigger sounds
409	for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) {
410		$soundList = new CComboBox('messages[sounds.'.$severity.']', $data['messages']['sounds.'.$severity]);
411		foreach ($zbxSounds as $filename => $file) {
412			$soundList->addItem($file, $filename);
413		}
414
415		$triggersTable->addRow([
416			(new CCheckBox('messages[triggers.severities]['.$severity.']'))
417				->setLabel(getSeverityName($severity, $data['config']))
418				->setChecked(array_key_exists($severity, $data['messages']['triggers.severities']))
419				->setUncheckedValue(0),
420			[
421				$soundList,
422				(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
423				(new CButton('start', _('Play')))
424					->addClass(ZBX_STYLE_BTN_GREY)
425					->onClick("javascript: testUserSound('messages_sounds.".$severity."');")
426					->removeId(),
427				(new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN),
428				(new CButton('stop', _('Stop')))
429					->addClass(ZBX_STYLE_BTN_GREY)
430					->onClick('javascript: AudioControl.stop();')
431					->removeId()
432			]
433		]);
434
435		zbx_subarray_push($msgVisibility, 1, 'messages[triggers.severities]['.$severity.']');
436		zbx_subarray_push($msgVisibility, 1, 'messages[sounds.'.$severity.']');
437	}
438
439	$userMessagingFormList
440		->addRow(_('Trigger severity'), $triggersTable, 'triggers_row')
441		->addRow(_('Show suppressed problems'),
442			(new CCheckBox('messages[show_suppressed]'))
443				->setChecked($data['messages']['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE)
444				->setUncheckedValue(ZBX_PROBLEM_SUPPRESSED_FALSE)
445		);
446}
447else {
448	$userMessagingFormList = null;
449}
450
451// append form lists to tab
452$userTab = new CTabView();
453if (!$data['form_refresh']) {
454	$userTab->setSelected(0);
455}
456$userTab->addTab('userTab', _('User'), $userFormList);
457if ($userMediaFormList) {
458	$userTab->addTab('mediaTab', _('Media'), $userMediaFormList);
459}
460
461// Permissions tab.
462if (!$data['is_profile']) {
463	$permissionsFormList = new CFormList('permissionsFormList');
464
465	$userTypeComboBox = new CComboBox('user_type', $data['user_type'], 'submit();', [
466		USER_TYPE_ZABBIX_USER => user_type2str(USER_TYPE_ZABBIX_USER),
467		USER_TYPE_ZABBIX_ADMIN => user_type2str(USER_TYPE_ZABBIX_ADMIN),
468		USER_TYPE_SUPER_ADMIN => user_type2str(USER_TYPE_SUPER_ADMIN)
469	]);
470
471	if ($data['userid'] != 0 && bccomp(CWebUser::$data['userid'], $data['userid']) == 0) {
472		$userTypeComboBox->setEnabled(false);
473		$permissionsFormList->addRow(_('User type'), [$userTypeComboBox, SPACE, new CSpan(_('User can\'t change type for himself'))]);
474		$userForm->addItem((new CVar('user_type', $data['user_type']))->removeId());
475	}
476	else {
477		$permissionsFormList->addRow(_('User type'), $userTypeComboBox);
478	}
479
480	$permissions_table = (new CTable())
481		->setAttribute('style', 'width: 100%;')
482		->setHeader([_('Host group'), _('Permissions')]);
483
484	if ($data['user_type'] == USER_TYPE_SUPER_ADMIN) {
485		$permissions_table->addRow([italic(_('All groups')), permissionText(PERM_READ_WRITE)]);
486	}
487	else {
488		foreach ($data['groups_rights'] as $groupid => $group_rights) {
489			if (array_key_exists('grouped', $group_rights) && $group_rights['grouped']) {
490				$group_name = ($groupid == 0)
491					? italic(_('All groups'))
492					: [$group_rights['name'], SPACE, italic('('._('including subgroups').')')];
493			}
494			else {
495				$group_name = $group_rights['name'];
496			}
497			$permissions_table->addRow([$group_name, permissionText($group_rights['permission'])]);
498		}
499	}
500
501	$permissionsFormList
502		->addRow(_('Permissions'),
503			(new CDiv($permissions_table))
504				->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR)
505				->setAttribute('style', 'min-width: '.ZBX_TEXTAREA_BIG_WIDTH.'px;')
506		)
507		->addInfo(_('Permissions can be assigned for user groups only.'));
508
509	$userTab->addTab('permissionsTab', _('Permissions'), $permissionsFormList);
510}
511
512if ($userMessagingFormList) {
513	$userTab->addTab('messagingTab', _('Messaging'), $userMessagingFormList);
514}
515
516// append buttons to form
517if ($data['userid'] != 0) {
518	$buttons = [
519		new CButtonCancel()
520	];
521
522	if (!$data['is_profile']) {
523		$deleteButton = new CButtonDelete(_('Delete selected user?'), url_param('form').url_param('userid'));
524		if (bccomp(CWebUser::$data['userid'], $data['userid']) == 0) {
525			$deleteButton->setAttribute('disabled', 'disabled');
526		}
527
528		array_unshift($buttons, $deleteButton);
529	}
530
531	$userTab->setFooter(makeFormFooter(new CSubmit('update', _('Update')), $buttons));
532}
533else {
534	$userTab->setFooter(makeFormFooter(
535		new CSubmit('add', _('Add')),
536		[new CButtonCancel()]
537	));
538}
539
540// append tab to form
541$userForm->addItem($userTab);
542
543// append form to widget
544$userWidget->addItem($userForm);
545
546return $userWidget;
547