<?php
/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/


require_once __DIR__.'/../../include/CWebTest.php';

/**
 * @backup users
 *
 * @onBefore prepareJitMedia
 *
 * @dataSource LoginUsers
 */
class testFormUserLdapMediaJit extends CWebTest {

	/**
	 * Attach MessageBehavior and TableBehavior to the test.
	 *
	 * @return array
	 */
	public function getBehaviors() {
		return [
			CMessageBehavior::class,
			CTableBehavior::class
		];
	}

	protected static $provisioned_media_count;

	const HASH_SQL = 'SELECT * FROM media';
	const LDAP_SERVER_NAME = 'TEST';
	const MEDIA_MAPPING_REMOVE = 'Media mapping with severity: all';
	const DELETE_MEDIA = 'Zammad';
	const MEDIA_MAPPING_EDIT_TYPE_1 = 'Media VictorOps for a type update';
	const MEDIA_MAPPING_EDIT_TYPE_2 = 'Media ServiceNow for a type update';
	const MEDIA_MAPPING_EDIT_TYPE_3 = 'Media Rocket.Chat for a different parameter update';
	const MEDIA_MAPPING_EDIT_TYPE_4 = 'Media OTRS CE for multiple media update';
	const MEDIA_MAPPING_EDIT_TYPE_5 = 'Media MantisBT for attribute update';

	/**
	 * Enable media types before test.
	 */
	public function prepareJitMedia() {
		$mediatypeids = CDBHelper::getAll('SELECT mediatypeid FROM media_type WHERE name IN (\'iTop\', \'SMS\','.
				' \'MS Teams Workflow\', \'Slack\', \'OTRS\', \'Opsgenie\', \'Brevis.one\', \'Github\', \'Discord\','.
				' \'iLert\', \'SIGNL4\', \'SysAid\', \'Jira\', \'Line\', \'Email\', \'PagerDuty\', \'Pushover\','.
				' \'Telegram\', \'Redmine\', \'Zammad\', \'VictorOps\', \'ServiceNow\')'
		);

		$update_api = [];

		foreach ($mediatypeids as $i => $mediatype) {
			$update_api[$i]['mediatypeid'] = $mediatype['mediatypeid'];
			$update_api[$i]['status'] = 0;
		}

		CDataHelper::call('mediatype.update', $update_api);

		$provisioned_media = [
			[
				'name' => self::MEDIA_MAPPING_REMOVE,
				'mediatypeid' => 42, // MS Teams Workflow.
				'attribute' => 'uid',
				'severity' => 63 // All severity options selected.
			],
			[
				'name' => 'Media mapping with severity: none',
				'mediatypeid' => 21, // OTRS.
				'attribute' => 'uid',
				'severity' => 0 // None.
			],
			[
				'name' => 'Enabled media type Opsgenie',
				'mediatypeid' => 6, // Opsgenie.
				'attribute' => 'uid'
			],
			[
				'name' => 'Enabled media that is disabled in Media types',
				'mediatypeid' => 17, // Zendesk.
				'attribute' => 'uid'
			],
			[
				'name' => 'Disabled media that is enabled in Media types',
				'mediatypeid' => 19, // Zammad.
				'attribute' => 'uid',
				'active' => 1
			],
			[
				'name' => self::MEDIA_MAPPING_EDIT_TYPE_1,
				'mediatypeid' => 28, // VictorOps.
				'attribute' => 'uid'
			],
			[
				'name' => self::MEDIA_MAPPING_EDIT_TYPE_2,
				'mediatypeid' => 18, // ServiceNow.
				'attribute' => 'uid'
			],
			[
				'name' => self::MEDIA_MAPPING_EDIT_TYPE_3,
				'mediatypeid' => 27, // Rocket.Chat.
				'attribute' => 'uid'
			],
			[
				'name' => self::MEDIA_MAPPING_EDIT_TYPE_4,
				'mediatypeid' => 39, // OTRS CE.
				'attribute' => 'uid'
			],
			[
				'name' => self::MEDIA_MAPPING_EDIT_TYPE_5,
				'mediatypeid' => 41, // OTRS CE.
				'attribute' => 'uid'
			]
		];
		self::$provisioned_media_count = count($provisioned_media);

		CDataHelper::call('userdirectory.create', [
			[
				'idp_type' => IDP_TYPE_LDAP,
				'name' => self::LDAP_SERVER_NAME,
				'host' => 'qa-ldap.zabbix.sandbox',
				'base_dn' => 'dc=zbx,dc=local',
				'port' => 389,
				'search_attribute' => 'uid',
				'bind_password' => PHPUNIT_LDAP_BIND_PASSWORD,
				'provision_status' => JIT_PROVISIONING_ENABLED,
				'provision_groups' => [
					[
						'name' => '*',
						'roleid' => 2, // Admin.
						'user_groups' => [
							[
								'usrgrpid' => 7 //Zabbix administrators.
							]
						]
					]
				],
				'provision_media' => $provisioned_media
			]
		]);

		CDataHelper::call('authentication.update', [
				'authentication_type' => SMTP_AUTHENTICATION_NORMAL,
				'ldap_auth_enabled' => ZBX_AUTH_LDAP_ENABLED,
				'disabled_usrgrpid' => 9, // Disabled.
				'ldap_jit_status' => JIT_PROVISIONING_ENABLED
		]);
	}

	public function testFormUserLdapMediaJit_CheckProvisionedMediaLayout() {
		// Media types to appear after the provisioning.
		$media_types = ['MantisBT', 'MS Teams Workflow', 'Opsgenie', 'OTRS', 'OTRS CE', 'Rocket.Chat', 'ServiceNow',
				'VictorOps', 'Zammad', 'Zendesk'
		];

		$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);
		$this->page->open('zabbix.php?action=userprofile.notification.edit')->waitUntilReady();

		// Check that the informative message about JIT provisioning is present.
		$this->assertMessage('Warning', null, 'This user is IdP provisioned. Manual changes for provisioned fields'.
				' are not allowed.'
		);

		$media_table = $this->query('id:userprofile-notification-form')->asTable()->one();

		// Check that correct amount of media is provisioned.
		$this->assertEquals(self::$provisioned_media_count, $media_table->getRows()->count());

		// Check that count of media is correctly displayed in the tab.
		$this->assertEquals(self::$provisioned_media_count, $this->query('id:userprofile-notification-form')
				->waitUntilVisible()->asForm()->one()->query('xpath:.//a[text()="Media"]')->one()
				->getAttribute('data-indicator-value')
		);

		// Check that only edit action is enabled for provisioned media.
		foreach ($media_types as $media_type) {
			$row = $media_table->findRow('Type', $media_type);
			$this->assertFalse($row->query('button:Remove')->one()->isClickable());
			$this->assertTrue($row->query('button:Edit')->one()->isClickable());
		}

		// Check the pressence and amount of hintboxes in media table for disabled media.
		$media_with_hints = ['MantisBT', 'OTRS CE', 'Rocket.Chat', 'Zendesk'];

		foreach ($media_with_hints as $media_type) {
			$row = $media_table->findRow('Type', $media_type, true);
			$this->assertTrue($row->getColumn('Type')
					->query('xpath:.//button['.CXPathHelper::fromClass('zi-i-warning').']')->one()->isValid()
			);
			$this->assertEquals('Media type disabled by Administration.', $row->getColumn('Type')
					->query('tag:button')->one()->getAttribute('data-hintbox-contents')
			);
		}

		$this->assertEquals(count($media_with_hints),
				$media_table->query('xpath:.//button['.CXPathHelper::fromClass('zi-i-warning').']')->count()
		);

		// Check that Type and Send to fields are read-only for provisioned media.
		$media_table->findRow('Type', 'MS Teams Workflow')->getColumn('Actions')->query('button:Edit')->one()->click();
		$media_form = COverlayDialogElement::find()->one()->waitUntilReady()->asForm();

		foreach (['Type', 'Send to'] as $field) {
			$this->assertTrue($media_form->getField($field)->isEnabled(false));
		}
	}

	public function getMediaEditData() {
		return [
			// #0 Check that When active is a mandatory field.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'When active' => ''
					],
					'message' => 'Incorrect value for field "period": a time period is expected.',
					'media' => 'MS Teams Workflow'
				]
			],
			// #1 Invalid characters in When active.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'When active' => 'test'
					],
					'message' => 'Incorrect value for field "period": a time period is expected.',
					'media' => 'MS Teams Workflow'
				]
			],
			// #2 Invalid When active value.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'When active' => '1-8,11:11-22:22'
					],
					'message' => 'Incorrect value for field "period": a time period is expected.',
					'media' => 'MS Teams Workflow'
				]
			],
			// #3 Invalid When active value.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'When active' => '6-5, 11:11-22:22'
					],
					'message' => 'Incorrect value for field "period": a time period is expected.',
					'media' => 'MS Teams Workflow'
				]
			],
			// #4 Invalid When active value.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'When active' => '0-1, 00:00-11:11'
					],
					'message' => 'Incorrect value for field "period": a time period is expected.',
					'media' => 'MS Teams Workflow'
				]
			],
			// #5 Invalid When active value.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'When active' => '1-7, 22:22-22:21'
					],
					'message' => 'Incorrect value for field "period": a time period is expected.',
					'media' => 'MS Teams Workflow'
				]
			],
			// #6 Invalid When active value.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'When active' => '1-7, 00:00-24:01'
					],
					'message' => 'Incorrect value for field "period": a time period is expected.',
					'media' => 'MS Teams Workflow'
				]
			],
			// #7 Space used as When active value.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'When active' => ' '
					],
					'message' => 'Incorrect value for field "period": a time period is expected.',
					'media' => 'MS Teams Workflow'
				]
			],
			// #8 Change editable fields - user macro in When active field.
			[
				[
					'expected' => TEST_GOOD,
					'fields' => [
						'When active' => '{$TEST}'
					],
					'media' => 'Zendesk',
					'check_configuration' => [
						'Use if severity' => [
							'Not classified',
							'Information',
							'Warning',
							'Average',
							'High',
							'Disaster'
						],
						'When active' => '{$TEST}',
						'Enabled' => false
					]
				]
			],
			// #9 Change editable fields - select all severities.
			[
				[
					'expected' => TEST_GOOD,
					'fields' => [
						'Use if severity' => [
							'Not classified',
							'Information',
							'Warning',
							'Average',
							'High',
							'Disaster'
						],
						'Enabled' => true
					],
					'media' => 'OTRS',
					'check_configuration' => [
						'Use if severity' => [
							'Not classified',
							'Information',
							'Warning',
							'Average',
							'High',
							'Disaster'
						],
						'When active' => '1-7,00:00-24:00',
						'Enabled' => true
					]
				]
			],
			// #10 Change editable fields - unselect all severities.
			[
				[
					'expected' => TEST_GOOD,
					'fields' => [
						'Use if severity' => []
					],
					'media' => 'MS Teams Workflow',
					'check_configuration' => [
						'Use if severity' => [],
						'When active' => '1-7,00:00-24:00',
						'Enabled' => true
					]
				]
			],
			// #11 Change editable fields - disable media which is enabled.
			[
				[
					'expected' => TEST_GOOD,
					'fields' => [
						'Enabled' => false
					],
					'media' => 'Opsgenie',
					'check_configuration' => [
						'Use if severity' => [
							'Not classified',
							'Information',
							'Warning',
							'Average',
							'High',
							'Disaster'
						],
						'When active' => '1-7,00:00-24:00',
						'Enabled' => false
					]
				]
			],
			// #12 Change editable fields - enable previously disabled media.
			[
				[
					'expected' => TEST_GOOD,
					'fields' => [
						'Enabled' => true
					],
					'media' => 'Zammad',
					'check_configuration' => [
						'Use if severity' => [
							'Not classified',
							'Information',
							'Warning',
							'Average',
							'High',
							'Disaster'
						],
						'When active' => '1-7,00:00-24:00',
						'Enabled' => true
					]
				]
			]
		];
	}

	/**
	 * @dataProvider getMediaEditData
	 */
	public function testFormUserLdapMediaJit_CheckEditableFields($data) {
		if ($data['expected'] === TEST_BAD) {
			$old_hash = CDBHelper::getHash(self::HASH_SQL);
		}

		// Log in as the LDAP provisioned user.
		$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);
		$this->page->open('zabbix.php?action=userprofile.notification.edit');

		// Close the warning message, to not affect further message check.
		$this->query('class:btn-overlay-close')->one()->click();

		$form = $this->query('id:userprofile-notification-form')->waitUntilVisible()->asForm()->one();
		$media_field = $form->getField('Media')->asTable();
		$row = $media_field->findRow('Type', $data['media']);
		$row->getColumn('Actions')->query('button:Edit')->one()->click();

		$dialog = COverlayDialogElement::find()->one()->waitUntilReady();
		$media_form = $dialog->asForm();
		$media_form->fill($data['fields']);
		$media_form->submit();

		if ($data['expected'] === TEST_BAD) {
			$this->assertMessage(TEST_BAD, null, $data['message']);
			$dialog->close();
		}

		$form->query('button:Update')->one()->click();
		$this->assertMessage(TEST_GOOD, 'User updated');

		if ($data['expected'] === TEST_BAD) {
			$this->assertEquals($old_hash, CDBHelper::getHash(self::HASH_SQL));
		}
		else {
			$this->page->logout();

			// Log in as the Super admin and provision the LDAP user.
			$this->page->login()->open('zabbix.php?action=user.list');
			$this->provisionLdapUser();
			$this->page->logout();

			// Log in as the provisioned user, to check that changed fields are not affected by the provisioning.
			$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);
			$this->page->open('zabbix.php?action=userprofile.notification.edit');
			$this->checkMediaConfiguration($data, $data['media'], PHPUNIT_LDAP_USERNAME,
					'check_configuration', 'id:userprofile-notification-form'
			);
		}
	}

	/**
	 * Check that LDAP provisioned user can add and remove non-provisioned media.
	 */
	// TODO: Uncomment this check, after ZBX-26064 is fixed.
	/*
	public function testFormUserLdapMediaJit_AddRemoveMedia() {
		// Media type configuration.
		$data = [
			'fields' => [
				'Type' => 'SMS',
				'Send to' => 'test',
				'When active' => '1-7,00:00-24:00',
				'Use if severity' => [
					'Not classified',
					'Information',
					'Warning',
					'Average',
					'High',
					'Disaster'
				],
				'Enabled' => true
			]
		];

		$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);
		$this->page->open('zabbix.php?action=userprofile.notification.edit');

		$form = $this->query('id:userprofile-notification-form')->waitUntilVisible()->asForm()->one();

		$this->query('button:Add')->one()->click();
		$dialog = COverlayDialogElement::find()->one()->waitUntilReady();
		$media_form = $dialog->asForm();
		$media_form->fill(['Type' => $data['fields']['Type'], 'Send to' => $data['fields']['Send to']]);

		$media_form->submit();
		$dialog->ensureNotPresent();
		$form->query('button:Update')->one()->click();
		$this->assertMessage(TEST_GOOD, 'User updated');

		// Check the media type that was added.
		$this->page->open('zabbix.php?action=userprofile.notification.edit');
		$this->checkMediaConfiguration($data, $data['fields']['Type'], $data['fields']['Send to']);
		$this->page->logout();

		// Provision LDAP user.
		$this->page->login()->open('zabbix.php?action=user.list');
		$this->provisionLdapUser();
		$this->page->logout();

		// Log in as LDAP user and check that added media is still present.
		$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);
		$this->page->open('zabbix.php?action=userprofile.notification.edit');
		$this->checkMediaConfiguration($data, $data['fields']['Type'], $data['fields']['Send to']);

		// Check that media can be removed by LDAP provisioned user.
		$media_field = $this->query('id:userprofile-notification-form')->waitUntilVisible()->asForm()->one()
				->getField('Media')->asTable();
		$row = $media_field->findRow('Type', $data['fields']['Type']);
		$row->getColumn('Actions')->query('button:Remove')->one()->click();
		$form->query('button:Update')->one()->click();
		$this->assertMessage(TEST_GOOD, 'User updated');

		// Check that media is no longer present in the list.
		$this->page->open('zabbix.php?action=userprofile.notification.edit');
		$this->assertFalse($form->getField('Media')->asTable()->findRow('Type', $data['fields']['Type'])->isPresent());
	}
	*/

	public function getUpdateMediaMappings() {
		return [
			// #0 Media type update to other enabled media type.
			[
				[
					'media_types' => [
						[
							'name' => self::MEDIA_MAPPING_EDIT_TYPE_1,
							'configuration' => [
								'fields' => [
									'Type' => 'VictorOps',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => true
								]
							],
							'update' => [
								'Media type' => 'Github'
							],
							'expected' => [
								'fields' => [
									'Type' => 'Github',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => true
								]
							]
						]
					]
				]
			],
			// #1 Media type update to other disabled media type.
			[
				[
					'media_types' => [
						[
							'name' => self::MEDIA_MAPPING_EDIT_TYPE_2,
							'configuration' => [
								'fields' => [
									'Type' => 'ServiceNow',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => true
								]
							],
							'update' => [
								'Media type' => 'Mattermost'
							],
							'expected' => [
								'fields' => [
									'Type' => 'Mattermost',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							]
						]
					]
				]
			],
			// #2 Media type severity update: severity.
			[
				[
					'media_types' => [
						[
							'name' => self::MEDIA_MAPPING_EDIT_TYPE_3,
							'configuration' => [
								'fields' => [
									'Type' => 'Rocket.Chat',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							],
							'update' => [
								'Use if severity' => []
							],
							'expected' => [
								'fields' => [
									'Type' => 'Rocket.Chat',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							]
						]
					]
				]
			],
			// #3 Media type status update.
			[
				[
					'media_types' => [
						[
							'name' => self::MEDIA_MAPPING_EDIT_TYPE_3,
							'configuration' => [
								'fields' => [
									'Type' => 'Rocket.Chat',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							],
							'update' => [
								'Create enabled' => true
							],
							'expected' => [
								'fields' => [
									'Type' => 'Rocket.Chat',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							]
						]
					]
				]
			],
			// #4 Media type update When active update.
			[
				[
					'media_types' => [
						[
							'name' => self::MEDIA_MAPPING_EDIT_TYPE_3,
							'configuration' => [
								'fields' => [
									'Type' => 'Rocket.Chat',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							],
							'update' => [
								'When active' => '1-5,00:00-22:00'
							],
							'expected' => [
								'fields' => [
									'Type' => 'Rocket.Chat',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							]
						]
					]
				]
			],
			// #5 Several media type mapping update.
			[
				[
					'media_types' => [
						[
							'name' => self::MEDIA_MAPPING_EDIT_TYPE_4,
							'configuration' => [
								'fields' => [
									'Type' => 'OTRS CE',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							],
							'update' => [
								'Media type' => 'SysAid'
							],
							'expected' => [
								'fields' => [
									'Type' => 'SysAid',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => true
								]
							]
						],
						[
							'name' => self::MEDIA_MAPPING_EDIT_TYPE_3,
							'configuration' => [
								'fields' => [
									'Type' => 'Rocket.Chat',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							],
							'update' => [
								'Media type' => 'MS Teams',
								'Use if severity' => ['High', 'Disaster']
							],
							'expected' => [
								'fields' => [
									'Type' => 'MS Teams',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							]
						]
					]
				]
			],
			// #6 Media type attribute change.
			[
				[
					'media_types' => [
						[
							'name' => self::MEDIA_MAPPING_EDIT_TYPE_5,
							'configuration' => [
								'fields' => [
									'Type' => 'MantisBT',
									'Send to' => PHPUNIT_LDAP_USERNAME,
									'When active' => '1-7,00:00-24:00',
									'Use if severity' => [
										'Not classified',
										'Information',
										'Warning',
										'Average',
										'High',
										'Disaster'
									],
									'Enabled' => false
								]
							],
							'update' => [
								'Attribute' => 'not_existing_attribute'
							]
						]
					]
				]
			]
		];
	}

	/**
	 * @dataProvider getUpdateMediaMappings
	 *
	 * Function to check that provisioned user's media is updated accordingly to media mapping.
	 */
	public function testFormUserLdapMediaJit_UpdateMediaMapping($data) {
		// Log in as the LDAP user, to make sure, that user is provisioned.
		$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);
		$this->page->logout();

		// Open media mapping to update.
		$form = $this->openLdapForm();
		$table = $form->query('id:ldap-servers')->asTable()->one();
		$table->query('link:'.self::LDAP_SERVER_NAME)->one()->click();
		$dialog = COverlayDialogElement::find()->waitUntilReady()->one();

		foreach ($data['media_types'] as $media_type) {
			$media_table = $dialog->query('id:ldap-media-type-mapping-table')->asTable()->one();
			$media_table->query('link', $media_type['name'])->one()->click();
			$media_form = COverlayDialogElement::find()->all()->last()->asForm();
			$media_form->fill($media_type['update']);
			$media_form->submit();
		}

		$dialog->query('button:Update')->one()->click();
		$form->submit();

		// Check that no changes are present until user is provisioned.
		$this->page->open('zabbix.php?action=user.list')->waitUntilReady();
		$this->query('link:'.PHPUNIT_LDAP_USERNAME)->one()->click();
		$this->assertEquals(self::$provisioned_media_count, $this->getUserMediaTable()->getRows()->count());

		foreach ($data['media_types'] as $media_type) {
			$this->checkMediaConfiguration($media_type['configuration'], $media_type['configuration']['fields']['Type'],
					PHPUNIT_LDAP_USERNAME
			);
		}

		// Provision the LDAP user.
		$this->page->open('zabbix.php?action=user.list');
		$this->provisionLdapUser();

		$this->page->open('zabbix.php?action=user.list')->waitUntilReady();
		$this->query('link:'.PHPUNIT_LDAP_USERNAME)->one()->click();
		$user_media_table = $this->getUserMediaTable();

		foreach ($data['media_types'] as $media_type) {
			if (array_key_exists('Attribute', $media_type['update'])) {
				$this->assertFalse($user_media_table->findRow('Type', '	MantisBT', true)->isPresent());
				$this->assertEquals(self::$provisioned_media_count - 1, $user_media_table->getRows()->count());
			}
			else {
				$this->checkMediaConfiguration($media_type['expected'], $media_type['expected']['fields']['Type'],
						PHPUNIT_LDAP_USERNAME
				);
			}
		}
	}

	public function getNewMediaMappings() {
		return [
			// #0 Media type severity - Not classified.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - Not classified',
						'Media type' => 'SMS',
						'Attribute' => 'uid',
						'Use if severity' => ['Not classified']
					],
					'expected' => [
						'fields' => [
							'Type' => 'SMS',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => ['Not classified'],
							'Enabled' => true
						]
					]
				]
			],
			// #1 Media type severity - Information.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - Information',
						'Media type' => 'Brevis.one',
						'Attribute' => 'uid',
						'Use if severity' => ['Information']
					],
					'expected' => [
						'fields' => [
							'Type' => 'Brevis.one',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => ['Information'],
							'Enabled' => true
						]
					]
				]
			],
			// #2 Media type severity - Warning.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - Warning',
						'Media type' => 'Slack',
						'Attribute' => 'uid',
						'Use if severity' => ['Warning']
					],
					'expected' => [
						'fields' => [
							'Type' => 'Slack',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => ['Warning'],
							'Enabled' => true
						]
					]
				]
			],
			// #3 Media type severity - Average.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - Average',
						'Media type' => 'Jira',
						'Attribute' => 'uid',
						'Use if severity' => ['Average']
					],
					'expected' => [
						'fields' => [
							'Type' => 'Jira',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => ['Average'],
							'Enabled' => true
						]
					]
				]
			],
			// #4 Media type severity - High.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - High',
						'Media type' => 'iLert',
						'Attribute' => 'uid',
						'Use if severity' => ['High']
					],
					'expected' => [
						'fields' => [
							'Type' => 'iLert',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => ['High'],
							'Enabled' => true
						]
					]
				]
			],
			// #5 Media type severity - Disaster.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - Disaster',
						'Media type' => 'Pushover',
						'Attribute' => 'uid',
						'Use if severity' => ['Disaster']
					],
					'expected' => [
						'fields' => [
							'Type' => 'Pushover',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => ['Disaster'],
							'Enabled' => true
						]
					]
				]
			],
			// #6 Media type severity - No severity.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - no severity',
						'Media type' => 'Telegram',
						'Attribute' => 'uid',
						'Use if severity' => []
					],
					'expected' => [
						'fields' => [
							'Type' => 'Telegram',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => [],
							'Enabled' => true
						]
					]
				]
			],
			// #7 Media type severity - All severity.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - All severity',
						'Media type' => 'Redmine',
						'Attribute' => 'uid',
						'Use if severity' => ['Not classified', 'Information', 'Warning', 'Average', 'High', 'Disaster']
					],
					'expected' => [
						'fields' => [
							'Type' => 'Redmine',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => [
								'Not classified',
								'Information',
								'Warning',
								'Average',
								'High',
								'Disaster'
							],
							'Enabled' => true
						]
					]
				]
			],
			// #8 When active - custom value.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - custom when active',
						'Media type' => 'SIGNL4',
						'Attribute' => 'uid',
						'When active' => '5-7,01:00-23:30'
					],
					'expected' => [
						'fields' => [
							'Type' => 'SIGNL4',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '5-7,01:00-23:30',
							'Use if severity' => [
								'Not classified',
								'Information',
								'Warning',
								'Average',
								'High',
								'Disaster'
							],
							'Enabled' => true
						]
					]
				]
			],
			// #9 When active - user macro syntax.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - when active with user macro',
						'Media type' => 'Discord',
						'Attribute' => 'uid',
						'When active' => '{$TEST}',
						'Use if severity' => ['Not classified', 'Information', 'Warning', 'Average', 'High', 'Disaster']
					],
					'expected' => [
						'fields' => [
							'Type' => 'Discord',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '{$TEST}',
							'Use if severity' => [
								'Not classified',
								'Information',
								'Warning',
								'Average',
								'High',
								'Disaster'
							],
							'Enabled' => true
						]
					]
				]
			],
			// #10 Create enabled: false.
			[
				[
					'provisioned' => true,
					'mapping' => [
						'Name' => 'Media mapping - disabled in LDAP',
						'Media type' => 'PagerDuty',
						'Attribute' => 'uid',
						'Create enabled' => false
					],
					'expected' => [
						'fields' => [
							'Type' => 'PagerDuty',
							'Send to' => PHPUNIT_LDAP_USERNAME,
							'When active' => '1-7,00:00-24:00',
							'Use if severity' => [
								'Not classified',
								'Information',
								'Warning',
								'Average',
								'High',
								'Disaster'
							],
							'Enabled' => false
						]
					]
				]
			],
			// #11 Email type media, which won't be added due to email validation.
			[
				[
					'provisioned' => false,
					'mapping' => [
						'Name' => 'Media mapping - Email',
						'Media type' => 'Email',
						'Attribute' => 'uid',
						'Use if severity' => []
					]
				]
			],
			// #12 Media type with non existing attribute.
			[
				[
					'provisioned' => false,
					'mapping' => [
						'Name' => 'Media mapping - incorrect attribute',
						'Media type' => 'Line',
						'Attribute' => 'test',
						'Use if severity' => []
					]
				]
			]
		];
	}

	/**
	 * Function to check that new media is added to the user after updating the mapping and provisioning.
	 *
	 * @dataProvider getNewMediaMappings
	 */
	public function testFormUserLdapMediaJit_AddMediaMapping($data) {
		$form = $this->openLdapForm();
		$table = $form->query('id:ldap-servers')->asTable()->one();
		$table->query('link:'.self::LDAP_SERVER_NAME)->one()->click();
		$dialog = COverlayDialogElement::find()->waitUntilReady()->one();
		$media_table = $dialog->query('id:ldap-media-type-mapping-table')->asTable()->one();
		$media_table->query('button:Add')->one()->click();
		$media_mapping_form = COverlayDialogElement::find()->all()->last()->asForm();

		$media_mapping_form->fill($data['mapping']);
		$media_mapping_form->submit();
		$dialog->query('button:Update')->one()->click();
		$form->submit();

		// Log in as LDAP user to check that media mapping was processed correctly.
		$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);
		$this->page->open('zabbix.php?action=userprofile.notification.edit');

		if ($data['provisioned'] === true) {
			$this->checkMediaConfiguration($data['expected'], $data['mapping']['Media type'], PHPUNIT_LDAP_USERNAME,
					'fields', 'id:userprofile-notification-form'
			);
		}
		else {
			$this->assertFalse($this->query('id:userprofile-notification-form')->asTable()->one()
					->findRow('Type', $data['mapping']['Media type'])->isPresent()
			);
		}
	}

	public function testFormUserLdapMediaJit_DeleteMediaType() {
		// Log in as the LDAP user, to make sure, that user is provisioned.
		$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);

		// Check that media type for deletion is present in user configuration.
		$this->page->open('zabbix.php?action=userprofile.notification.edit')->waitUntilReady();
		$this->assertTrue($this->query('id:userprofile-notification-form')->asTable()->one()
				->findRow('Type', self::DELETE_MEDIA, true)->isPresent()
		);
		$this->page->logout();

		// Delete media type that is used in LDAP media mapping.
		$this->page->login()->open('zabbix.php?action=mediatype.list')->waitUntilReady();
		$table = $this->getTable();
		$table->findRows('Name', self::DELETE_MEDIA)->select();
		$this->query('button:Delete')->one()->click();
		$this->page->acceptAlert();
		$this->assertMessage(TEST_GOOD, 'Media type deleted');

		// Check that media type is removed from LDAP user.
		$this->page->open('zabbix.php?action=user.list')->waitUntilReady();
		$this->query('link:'.PHPUNIT_LDAP_USERNAME)->one()->click();
		$this->assertFalse($this->getUserMediaTable()->findRow('Type', self::DELETE_MEDIA, true)->isPresent());
	}

	public function testFormUserLdapMediaJit_RemoveMediaMapping() {
		// Log in as the LDAP user, to make sure, that user is provisioned.
		$this->page->userLogin(PHPUNIT_LDAP_USERNAME, PHPUNIT_LDAP_USER_PASSWORD);
		$this->page->logout();

		// Remove media mapping from LDAP configurations.
		$form = $this->openLdapForm();
		$table = $form->query('id:ldap-servers')->asTable()->one();
		$table->query('link:'.self::LDAP_SERVER_NAME)->one()->click();
		$dialog = COverlayDialogElement::find()->waitUntilReady()->one();
		$media_table = $dialog->query('id:ldap-media-type-mapping-table')->asTable()->one();
		$media_table->findRow('Name', self::MEDIA_MAPPING_REMOVE, true)->query('button:Remove')->one()->click();
		$dialog->query('button:Update')->one()->click();
		$form->submit();

		// Check that media is not present for LDAP provisioned user.
		$this->page->open('zabbix.php?action=user.list')->waitUntilReady();
		$this->query('link:'.PHPUNIT_LDAP_USERNAME)->one()->click();
		$user_media_table = $this->getUserMediaTable();
		$this->assertFalse($user_media_table->findRow('Type', 'MS Teams Workflow', true)->isPresent());
	}

	/**
	 * Check media type configuration in user configuration form.
	 *
	 * @param array		$data				data provider
	 * @param string	$media_type			type of the media
	 * @param string	$send_to			send to parameter of the media
	 * @param string	$expected			name of the array with expected result
	 * @param string	$selector			selector for a media table
	 */
	protected function checkMediaConfiguration($data, $media_type, $send_to, $expected = 'fields',
			$selector = 'id:mediaTab') {
		// Check media type.
		$row = $this->query($selector)->asTable()->one()->findRow('Type', $media_type);

		$this->assertEquals($row->getColumn('Type')->getText(), $media_type);

		// Check the value of the "Send to" field.
		$this->assertFalse($row->query('xpath:./td[2]/span[@data-hintbox]')->one(false)->isValid());
		$get_send_to = $row->getColumn('Send to')->getText();
		$this->assertEquals($send_to, $get_send_to);

		// Check media active period.
		$when_active = $row->getColumn('When active')->getText();
		$this->assertEquals($when_active, CTestArrayHelper::get($data, $expected.'.When active', '1-7,00:00-24:00'));

		// Check media status.
		$get_status = $row->getColumn('Status')->getText();
		$status = CTestArrayHelper::get($data, $expected.'.Enabled', true) ? 'Enabled' : 'Disabled';
		$this->assertEquals($get_status, $status);

		// Check selected severities.
		$reference_severities = [
			'Not classified' => '1',
			'Information' => '2',
			'Warning' => '3',
			'Average' => '4',
			'High' => '5',
			'Disaster' => '6'
		];

		if (array_key_exists('Use if severity', $data[$expected])) {
			// Check that the passed severities are turned on.
			foreach ($data[$expected]['Use if severity'] as $used_severity) {
				$actual_severity = $row->query('xpath:./td[4]/div/span['.$reference_severities[$used_severity].']')
						->one()->getAttribute('data-hintbox-contents');
				$this->assertEquals($actual_severity, $used_severity.' (on)');
				unset($reference_severities[$used_severity]);
			}
			// Check that other severities are turned off.
			foreach ($reference_severities as $name => $unused_severity) {
				$actual_severity = $row->query('xpath:./td[4]/div/span['.$unused_severity.']')->one()
						->getAttribute('data-hintbox-contents');
				$this->assertEquals($name.' (off)', $actual_severity);
			}
		}
	}

	/**
	 * Function for opening LDAP configuration form.
	 *
	 * @return CFormElement
	 */
	protected function openLdapForm() {
		$this->page->login()->open('zabbix.php?action=authentication.edit');
		$form = $this->query('id:authentication-form')->asForm()->one();
		$form->selectTab('LDAP settings');

		return $form;
	}

	/**
	 * Function for provisioning the user.
	 */
	protected function provisionLdapUser() {
		$table = $this->getTable();
		$table->findRows('Username', PHPUNIT_LDAP_USERNAME)->select();
		$this->query('button:Provision now')->one()->click();
		$this->page->acceptAlert();
		$this->assertMessage(TEST_GOOD, 'Provisioning successful.', 'User "'.PHPUNIT_LDAP_USERNAME.'" provisioned.');
	}

	/**
	 * Function for selecting the user and getting the media table.
	 *
	 * @return CTableElement
	 */
	protected function getUserMediaTable() {
		$user_form = $this->query('id:user-form')->waitUntilVisible()->asForm()->one();
		$user_form->selectTab('Media');

		return $this->query('id:media-table')->asTable()->one();
	}
}