<?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 dirname(__FILE__).'/../include/CAPITest.php';
require_once __DIR__.'/../include/helpers/CTestDataHelper.php';

/**
 * @onBefore prepareTestData
 * @onAfter  cleanTestData
 */
class testAction extends CAPITest {

	public static function prepareTestData(): void {
		CTestDataHelper::createObjects([
			'template_groups' => [
				['name' => 'perm.tg1'],
				['name' => 'perm.tg2'],
				['name' => 'perm.tg3']
			],
			'host_groups' => [
				['name' => 'del.hg1'],
				['name' => 'perm.filter.condition.hg1'],
				['name' => 'perm.hg1'],
				['name' => 'perm.hg2'],
				['name' => 'perm.hg3'],
				['name' => 'perm.hg4'],
				['name' => 'perm.hg5'],
				['name' => 'perm.opcommand_grp.hg1'],
				['name' => 'perm.hg6'],
				['name' => 'perm.opgroup.hg1'],
				['name' => 'perm.opgroup.hg2']
			],
			'proxies' => [
				[
					'name' => 'del.p1',
					'operating_mode' => PROXY_OPERATING_MODE_ACTIVE
				]
			],
			'templates' => [
				[
					'host' => 'perm.filter.condition.t1',
					'groups' => ['groupid' => ':template_group:perm.tg1']
				],
				[
					'host' => 'perm.optemplate.t1',
					'groups' => ['groupid' => ':template_group:perm.tg2']
				],
				[
					'host' => 'perm.optemplate.t2',
					'groups' => ['groupid' => ':template_group:perm.tg3']
				]
			],
			'hosts' => [
				[
					'host' => 'perm.filter.condition.h1',
					'groups' => ['groupid' => ':host_group:perm.hg1']
				],
				[
					'host' => 'perm.h1',
					'groups' => ['groupid' => ':host_group:perm.hg2'],
					'items' => [
						['key_' => 'i1']
					]
				],
				[
					'host' => 'perm.opcommand_hst.h1',
					'groups' => ['groupid' => ':host_group:perm.hg6']
				]
			],
			'triggers' => [
				'perm.filter.condition.tg1(perm.h1(i1))' => [
					'description' => 'perm.filter.condition.tg1(perm.h1(i1))',
					'expression' => 'last(/perm.h1/i1)=0'
				]
			],
			'roles' => [
				['name' => 'r1', 'type' => USER_TYPE_ZABBIX_ADMIN]
			],
			'user_groups' => [
				[
					'name' => 'del.ug1',
					'hostgroup_rights' => [
						'id' => ':host_group:del.hg1',
						'permission' => PERM_READ
					]
				],
				[
					'name' => 'perm.opmessage_grp.ug1',
					'hostgroup_rights' => [
						'id' => ':host_group:perm.hg3',
						'permission' => PERM_READ
					]
				],
				[
					'name' => 'perm.ug1',
					'hostgroup_rights' => [
						'id' => ':host_group:perm.hg4',
						'permission' => PERM_READ
					]
				]
			],
			'users' => [
				[
					'username' => 'del.u1',
					'passwd' => '|-|e!1@ (/\)0rLD!',
					'usrgrps' => [
						['usrgrpid' => ':user_group:del.ug1']
					]
				],
				[
					'username' => 'perm.opmessage_usr.u1',
					'passwd' => '|-|e!1@ (/\)0rLD!',
					'usrgrps' => [
						['usrgrpid' => ':user_group:perm.ug1']
					]
				]
			],
			'scripts' => [
				[
					'name' => 'perm.opcommand.s1',
					'type' => ZBX_SCRIPT_TYPE_WEBHOOK,
					'scope' => ZBX_SCRIPT_SCOPE_ACTION,
					'command' => 'return value;',
					'groupid' => ':host_group:perm.hg5'
				]
			],
			'actions' => [
				[
					'name'=> 'del.trigger.action.1',
					'eventsource' => EVENT_SOURCE_TRIGGERS,
					'operations' => [
						[
							'operationtype' => OPERATION_TYPE_MESSAGE,
							'opmessage' => [],
							'opmessage_usr' => [
								['userid' => ':user:del.u1']
							]
						]
					]
				],
				[
					'name' => 'del.discovery.action.1',
					'eventsource' => EVENT_SOURCE_DISCOVERY,
					'filter' => [
						'evaltype' => CONDITION_EVAL_TYPE_AND_OR,
						'conditions' => [
							[
								'conditiontype' => ZBX_CONDITION_TYPE_PROXY,
								'operator' => CONDITION_OPERATOR_EQUAL,
								'value' => ':proxy:del.p1'
							]
						]
					],
					'operations' => [
						[
							'operationtype' => OPERATION_TYPE_MESSAGE,
							'opmessage' => [],
							'opmessage_grp' => [
								['usrgrpid' => ':user_group:del.ug1']
							]
						]
					]
				],
				[
					'name' => 'del.autoreg.action.1',
					'eventsource' => EVENT_SOURCE_AUTOREGISTRATION,
					'operations' => [
						[
							'operationtype' => OPERATION_TYPE_MESSAGE,
							'opmessage' => [],
							'opmessage_grp' => [
								['usrgrpid' => ':user_group:del.ug1']
							]
						]
					]
				],
				[
					'name' => 'del.internal.action.1',
					'eventsource' => EVENT_SOURCE_INTERNAL,
					'filter' => [
						'evaltype' => CONDITION_EVAL_TYPE_AND_OR,
						'conditions' => [
							[
								'conditiontype' => ZBX_CONDITION_TYPE_EVENT_TYPE,
								'operator' => CONDITION_OPERATOR_EQUAL,
								'value' => EVENT_TYPE_TRIGGER_UNKNOWN
							]
						]
					],
					'operations' => [
						[
							'operationtype' => OPERATION_TYPE_MESSAGE,
							'opmessage' => [],
							'opmessage_grp' => [
								['usrgrpid' => ':user_group:del.ug1']
							]
						]
					],
					'recovery_operations' => [
						[
							'operationtype' => OPERATION_TYPE_RECOVERY_MESSAGE,
							'opmessage' => []
						]
					]
				],
				[
					'name' => 'perm.trigger.action.1',
					'eventsource' => EVENT_SOURCE_TRIGGERS,
					'filter' => [
						'evaltype' => CONDITION_EVAL_TYPE_AND_OR,
						'conditions' => [
							[
								'conditiontype' => ZBX_CONDITION_TYPE_HOST_GROUP,
								'operator' => CONDITION_OPERATOR_EQUAL,
								'value' => ':host_group:perm.filter.condition.hg1'
							],
							[
								'conditiontype' => ZBX_CONDITION_TYPE_HOST,
								'operator' => CONDITION_OPERATOR_EQUAL,
								'value' => ':host:perm.filter.condition.h1'
							],
							[
								'conditiontype' => ZBX_CONDITION_TYPE_TRIGGER,
								'operator' => CONDITION_OPERATOR_EQUAL,
								'value' => ':trigger:perm.filter.condition.tg1(perm.h1(i1))'
							],
							[
								'conditiontype' => ZBX_CONDITION_TYPE_TEMPLATE,
								'operator' => CONDITION_OPERATOR_EQUAL,
								'value' => ':template:perm.filter.condition.t1'
							]
						]
					],
					'operations' => [
						[
							'operationtype' => OPERATION_TYPE_MESSAGE,
							'opmessage' => [],
							'opmessage_grp' => [
								['usrgrpid' => ':user_group:perm.opmessage_grp.ug1']
							],
							'opmessage_usr' => [
								['userid' => ':user:perm.opmessage_usr.u1']
							]
						],
						[
							'operationtype' => OPERATION_TYPE_COMMAND,
							'opcommand' => ['scriptid' => ':script:perm.opcommand.s1'],
							'opcommand_grp' => [
								['groupid' => ':host_group:perm.opcommand_grp.hg1']
							],
							'opcommand_hst' => [
								['hostid' => ':host:perm.opcommand_hst.h1']
							]
						]
					]
				],
				[
					'name' => 'perm.discovery.action.1',
					'eventsource' => EVENT_SOURCE_DISCOVERY,
					'operations' => [
						[
							'operationtype' => OPERATION_TYPE_GROUP_ADD,
							'opgroup' => [
								['groupid' => ':host_group:perm.opgroup.hg1']
							]
						],
						[
							'operationtype' => OPERATION_TYPE_GROUP_REMOVE,
							'opgroup' => [
								['groupid' => ':host_group:perm.opgroup.hg2']
							]
						],
						[
							'operationtype' => OPERATION_TYPE_TEMPLATE_ADD,
							'optemplate' => [
								['templateid' => ':template:perm.optemplate.t1']
							]
						],
						[
							'operationtype' => OPERATION_TYPE_TEMPLATE_REMOVE,
							'optemplate' => [
								['templateid' => ':template:perm.optemplate.t2']
							]
						]
					]
				]
			]
		]);

		CTestDataHelper::createObjects([
			'template_groups' => [
				['name' => 'completely.no.access.to.perm.trigger.action.1']
			],
			'host_groups' => [
				['name' => 'completely.no.access.to.perm.trigger.action.1']
			],
			'user_groups' => [
				[
					'name' => 'full.access.to.perm.trigger.action.1',
					'templategroup_rights' => [
						['id' => ':template_group:perm.tg1', 'permission' => PERM_READ]
					],
					'hostgroup_rights' => [
						['id' => ':host_group:perm.filter.condition.hg1', 'permission' => PERM_READ],
						['id' => ':host_group:perm.hg1', 'permission' => PERM_READ],
						['id' => ':host_group:perm.hg2', 'permission' => PERM_READ],
						['id' => ':host_group:perm.hg5', 'permission' => PERM_READ],
						['id' => ':host_group:perm.opcommand_grp.hg1', 'permission' => PERM_READ],
						['id' => ':host_group:perm.hg6', 'permission' => PERM_READ]
					]
				],
				[
					'name' => 'completely.no.access.to.perm.trigger.action.1',
					'templategroup_rights' => [
						['id' => ':template_group:completely.no.access.to.perm.trigger.action.1', 'permission' => PERM_READ]
					],
					'hostgroup_rights' => [
						['id' => ':host_group:completely.no.access.to.perm.trigger.action.1', 'permission' => PERM_READ]
					]
				],
				[
					'name' => 'full.access.to.perm.discovery.action.1',
					'templategroup_rights' => [
						['id' => ':template_group:perm.tg2', 'permission' => PERM_READ],
						['id' => ':template_group:perm.tg3', 'permission' => PERM_READ]
					],
					'hostgroup_rights' => [
						['id' => ':host_group:perm.opgroup.hg1', 'permission' => PERM_READ],
						['id' => ':host_group:perm.opgroup.hg2', 'permission' => PERM_READ]
					]
				],
				[
					'name' => 'partial.access.to.perm.discovery.action.1',
					'templategroup_rights' => [
						['id' => ':template_group:perm.tg2', 'permission' => PERM_READ]
					],
					'hostgroup_rights' => [
						['id' => ':host_group:perm.opgroup.hg2', 'permission' => PERM_READ]
					]
				]
			],
			'users' => [
				[
					'username' => 'full.access.to.perm.trigger.action.1',
					'passwd' => '|-|e!1@ (/\)0rLD!',
					'usrgrps' => [
						['usrgrpid' => ':user_group:full.access.to.perm.trigger.action.1'],
						['usrgrpid' => ':user_group:perm.opmessage_grp.ug1'],
						['usrgrpid' => ':user_group:perm.ug1']
					]
				],
				[
					'username' => 'completely.no.access.to.perm.trigger.action.1',
					'passwd' => '|-|e!1@ (/\)0rLD!',
					'usrgrps' => [
						['usrgrpid' => ':user_group:completely.no.access.to.perm.trigger.action.1']
					]
				],
				[
					'username' => 'partial.access.to.perm.trigger.action.1',
					'passwd' => '|-|e!1@ (/\)0rLD!',
					'usrgrps' => [
						['usrgrpid' => ':user_group:full.access.to.perm.trigger.action.1']
					]
				],
				[
					'username' => 'full.access.to.perm.discovery.action.1',
					'passwd' => '|-|e!1@ (/\)0rLD!',
					'usrgrps' => [
						['usrgrpid' => ':user_group:full.access.to.perm.discovery.action.1']
					]
				],
				[
					'username' => 'completely.no.access.to.perm.discovery.action.1',
					'passwd' => '|-|e!1@ (/\)0rLD!',
					'usrgrps' => [
						['usrgrpid' => ':user_group:completely.no.access.to.perm.trigger.action.1']
					]
				],
				[
					'username' => 'partial.access.to.perm.discovery.action.1',
					'passwd' => '|-|e!1@ (/\)0rLD!',
					'usrgrps' => [
						['usrgrpid' => ':user_group:partial.access.to.perm.discovery.action.1']
					]
				]
			]
		]);
	}

	public static function cleanTestData(): void {
		CTestDataHelper::cleanUp();
	}

	public static function getActionDeleteData() {
		return [
			[
				'actionids' => [],
				'expected_error' => 'Invalid parameter "/": cannot be empty.'
			],
			[
				'actionids' => [''],
				'expected_error' => 'Invalid parameter "/1": a number is expected.'
			],
			[
				'actionids' => ['abc'],
				'expected_error' => 'Invalid parameter "/1": a number is expected.'
			],
			[
				'actionids' => ['1.1'],
				'expected_error' => 'Invalid parameter "/1": a number is expected.'
			],
			[
				'actionids' => ['123456'],
				'expected_error' => 'No permissions to referred object or it does not exist!'
			],
			[
				'actionids' => [':action:del.trigger.action.1', ':action:del.trigger.action.1'],
				'expected_error' => static fn (): string => 'Invalid parameter "/2": value ('.CTestDataHelper::getConvertedValueReference(':action:del.trigger.action.1').') already exists.'
			],
			[
				'actionids' => [':action:del.trigger.action.1', 'abcd'],
				'expected_error' => 'Invalid parameter "/2": a number is expected.'
			],
			[
				'actionids' => [':action:del.trigger.action.1'],
				'expected_error' => null
			],
			[
				'actionids' => [':action:del.discovery.action.1'],
				'expected_error' => null
			],
			[
				'actionids' => [':action:del.autoreg.action.1'],
				'expected_error' => null
			],
			[
				'actionids' => [':action:del.internal.action.1'],
				'expected_error' => null
			]
		];
	}

	/**
	* @dataProvider getActionDeleteData
	*/
	public function testAction_Delete($actionids, $expected_error) {
		$converted_actionids = CTestDataHelper::getConvertedValueReferences($actionids);

		$this->call('action.delete', $converted_actionids, $expected_error);

		if ($expected_error === null) {
			CTestDataHelper::unsetDeletedObjectIds(array_diff($actionids, $converted_actionids));

			$db_actionids = array_keys(CAPIHelper::call('action.get', [
				'output' => [],
				'actionids' => $converted_actionids,
				'preservekeys' => true
			]));

			$this->assertSame([],
				array_intersect_key($actionids, array_intersect($converted_actionids, $db_actionids))
			);
		}
	}

	public static function getActionUserPermissionsData() {
		return [
			'User has permissions on all entities specified in trigger action' => [
				'login' => ['username' => 'full.access.to.perm.trigger.action.1', 'password'=> '|-|e!1@ (/\)0rLD!'],
				'actionids' => [':action:perm.trigger.action.1'],
				'expected_actionids' => [':action:perm.trigger.action.1']
			],
			'User has no permissions on any entity specified in trigger action' => [
				'login' => ['username' => 'completely.no.access.to.perm.trigger.action.1', 'password'=> '|-|e!1@ (/\)0rLD!'],
				'actionids' => [':action:perm.trigger.action.1'],
				'expected_actionids' => []
			],
			'User has permissions on some of the entities specified in trigger action' => [
				'login' => ['username' => 'partial.access.to.perm.trigger.action.1', 'password'=> '|-|e!1@ (/\)0rLD!'],
				'actionids' => [':action:perm.trigger.action.1'],
				'expected_actionids' => []
			],
			'User has permissions on all entities specified in discovery action' => [
				'login' => ['username' => 'full.access.to.perm.discovery.action.1', 'password'=> '|-|e!1@ (/\)0rLD!'],
				'actionids' => [':action:perm.discovery.action.1'],
				'expected_actionids' => [':action:perm.discovery.action.1']
			],
			'User has no permissions on any entity specified in discovery action' => [
				'login' => ['username' => 'completely.no.access.to.perm.discovery.action.1', 'password'=> '|-|e!1@ (/\)0rLD!'],
				'actionids' => [':action:perm.discovery.action.1'],
				'expected_actionids' => []
			],
			'User has permissions on some of the entities specified in discovery action' => [
				'login' => ['username' => 'partial.access.to.perm.discovery.action.1', 'password'=> '|-|e!1@ (/\)0rLD!'],
				'actionids' => [':action:perm.discovery.action.1'],
				'expected_actionids' => []
			]
		];
	}

	/**
	 * @dataProvider getActionUserPermissionsData
	 */
	public function testAction_Permissions(array $login, array $actionids, array $expected_actionids): void {
		$this->authorize($login['username'], $login['password']);

		CTestDataHelper::convertValueReferences($actionids);

		$result = $this->call('action.get', [
			'output' => [],
			'actionids' => $actionids,
			'preservekeys' => true
		], null);

		$converted_expected_actionids = CTestDataHelper::getConvertedValueReferences($expected_actionids);

		$db_actionids = array_keys($result['result']);

		foreach ($db_actionids as &$db_actionid) {
			$i = array_search($db_actionid, $converted_expected_actionids);

			if ($i !== false) {
				$db_actionid = $expected_actionids[$i];
			}
		}
		unset($db_actionid);

		sort($expected_actionids);
		sort($db_actionids);

		$this->assertSame($expected_actionids, $db_actionids);
	}
}