summaryrefslogtreecommitdiffstats
path: root/modules-available/permissionmanager/inc/permissionutil.inc.php
blob: 3daf422e875006947864471b0d11f687c96fcc99 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<?php

class PermissionUtil
{
	/**
	 * Check if the user has the given permission (for the given location).
	 *
	 * @param string $userid userid to check
	 * @param string $permissionid permissionid to check
	 * @param int|null $locationid locationid to check or null if the location should be disregarded
	 * @return bool true if user has permission, false if not
	 */
	public static function userHasPermission($userid, $permissionid, $locationid) {
		$locations = array();
		if (!is_null($locationid)) {
			$locations = Location::getLocationRootChain($locationid);
			if (count($locations) == 0) return false;
			else $locations[] = 0;
		}

		$res = Database::simpleQuery("SELECT permissionid, locationid FROM user_x_role
												INNER JOIN role_x_permission ON user_x_role.roleid = role_x_permission.roleid
												LEFT JOIN (SELECT roleid, COALESCE(locationid, 0) AS locationid FROM role_x_location) t1
													ON role_x_permission.roleid = t1.roleid
												WHERE user_x_role.userid = :userid", array("userid" => $userid));

		while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
			$userPermission = rtrim($row["permissionid"], ".*").".";
			if ((is_null($locationid) || (!is_null($row["locationid"]) && in_array($row["locationid"], $locations))) &&
				(substr($permissionid.".", 0, strlen($userPermission)) === $userPermission || $userPermission === ".")) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Get all locations where the user has the given permission.
	 *
	 * @param string $userid userid to check
	 * @param string $permissionid permissionid to check
	 * @return array array of locationids where the user has the given permission
	 */
	public static function getAllowedLocations($userid, $permissionid) {

		$res = Database::simpleQuery("SELECT permissionid, COALESCE(locationid, 0) AS locationid FROM user_x_role
												INNER JOIN role_x_permission ON user_x_role.roleid = role_x_permission.roleid
												INNER JOIN role_x_location ON role_x_permission.roleid = role_x_location.roleid
												WHERE user_x_role.userid = :userid", array("userid" => $userid));

		$allowedLocations = array();
		while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
			$userPermission = rtrim($row["permissionid"], ".*").".";
			if (substr($permissionid.".", 0, strlen($userPermission)) === $userPermission || $userPermission === ".") {
				$allowedLocations[$row["locationid"]] = 1;
			}
		}
		$allowedLocations = array_keys($allowedLocations);
		$locations = Location::getTree();
		if (in_array("0", $allowedLocations)) {
			$allowedLocations = array_map("intval", Location::extractIds($locations));
			$allowedLocations[] = 0;
		} else {
			$allowedLocations = self::getSublocations($locations, $allowedLocations);
		}
		return $allowedLocations;
	}

	/**
	 * Extend an array of locations by adding all sublocations.
	 *
	 * @param array $tree tree of all locations (structured like Location::getTree())
	 * @param array $locations the array of locationids to extend
	 * @return array extended array of locationids
	 */
	public static function getSublocations($tree, $locations) {
		$result = array_flip($locations);
		foreach ($tree as $location) {
			if (array_key_exists("children", $location)) {
				if (in_array($location["locationid"], $locations)) {
					$result += array_flip(Location::extractIds($location["children"]));
				} else {
					$result += array_flip(self::getSublocations($location["children"], $locations));
				}
			}
		}
		return array_keys($result);
	}

	/**
	 * Get all permissions of all active modules that have permissions in their permissions/permissions.json file.
	 *
	 * @return array permission tree as a multidimensional array
	 */
	public static function getPermissions()
	{
		$permissions = array();
		foreach (glob("modules/*/permissions/permissions.json", GLOB_NOSORT) as $file) {
			$data = json_decode(file_get_contents($file), true);
			if (!is_array($data))
				continue;
			preg_match('#^modules/([^/]+)/#', $file, $out);
			foreach( $data as $p => $data) {
				$description = Dictionary::translateFileModule($out[1], "permissions", $p);
				self::putInPermissionTree($out[1].".".$p, $data['location-aware'], $description, $permissions);
			}
		}
		ksort($permissions);
		global $MENU_CAT_OVERRIDE;
		$sortingOrder = $MENU_CAT_OVERRIDE;
		foreach ($permissions as $module => $v) $sortingOrder[Module::get($module)->getCategory()][] = $module;
		$permissions = array_replace(array_flip(call_user_func_array('array_merge', $sortingOrder)), $permissions);
		foreach ($permissions as $module => $v) if (is_int($v)) unset($permissions[$module]);


		return $permissions;
	}

	/**
	 * Place a permission into the given permission tree.
	 *
	 * @param string $permission the permission to place in the tree
	 * @param bool $locationAware whether this permissions can be restricted to specific locations only
	 * @param string $description the description of the permission
	 * @param array $tree the permission tree to modify
	 */
	private static function putInPermissionTree($permission, $locationAware, $description, &$tree)
	{
		$subPermissions = explode('.', $permission);
		foreach ($subPermissions as $subPermission) {
			if ($subPermission) {
				if (!array_key_exists($subPermission, $tree)) {
					$tree[$subPermission] = array();
				}
				$tree =& $tree[$subPermission];
			}
		}
		$tree = array('description' => $description, 'location-aware' => $locationAware, 'isLeaf' => true);
	}
}