perspectivelib.php 9.66 KB
Newer Older
1
<?php
2
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3
//
4 5 6
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
7

8
/**
9 10
 * PerspectiveLib
 *
11
 */
12 13
class PerspectiveLib
{
14 15 16
	private $perspectives;
	private $perspectivePreferences;

rjsmelo's avatar
rjsmelo committed
17 18 19 20
	/**
	 *
	 */
	function __construct()
21
	{
22 23 24 25
		$this->perspectives = TikiDb::get()->table('tiki_perspectives');
		$this->perspectivePreferences = TikiDb::get()->table('tiki_perspective_preferences');
	}

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
	/**
	 * @param $user
	 * @return int
	 */
	function get_preferred_perspective($user)
	{
		$perspectiveId = null;

		if(empty($user)) {
			return $perspectiveId;
		}
	
		$sql = "SELECT value FROM tiki_user_preferences WHERE prefName='perspective_preferred' AND user=?";
		$perspectiveId = TikiDb::get()->getOne($sql, [$user]);

		if(is_numeric($perspectiveId)) {
			return (int) $perspectiveId;
		}

		return $perspectiveId;
	}


rjsmelo's avatar
rjsmelo committed
49 50 51 52 53
	/**
	 * @param $prefs
	 * @return int
	 */
	function get_current_perspective($prefs)
54
	{
55 56 57 58
		global $user;
		$tikilib = TikiLib::lib('tiki');
		$perspectiveId = $this->get_preferred_perspective($user);

rjsmelo's avatar
rjsmelo committed
59
		if (isset($_REQUEST['perspectiveId'])) {
60
			$perspectiveId = (int) $_REQUEST['perspectiveId'];
rjsmelo's avatar
rjsmelo committed
61
		} elseif (isset($_SESSION['current_perspective'])) {
62 63 64 65 66
			$perspectiveId = (int) $_SESSION['current_perspective'];
		}

		if($perspectiveId) {
			return $perspectiveId;
67
		}
68

69 70 71
		if (method_exists($tikilib, "get_ip_address")) {
			$ip = $tikilib->get_ip_address();
		}
72

rjsmelo's avatar
rjsmelo committed
73 74
		foreach ($this->get_subnet_map($prefs) as $subnet => $perspective) {
			if ($this->is_in_subnet($ip, $subnet)) {
75 76 77 78
				return $perspective;
			}
		}

79
		$currentDomain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
rjsmelo's avatar
rjsmelo committed
80 81
		foreach ($this->get_domain_map($prefs) as $domain => $perspective) {
			if ($domain == $currentDomain) {
82
				$_SESSION['current_perspective'] = trim($perspective);
83
				$_SESSION['current_perspective_name'] = $this->get_perspective_name($_SESSION['current_perspective']);
84
				return $perspective;
85 86 87 88
			}
		}
	}

rjsmelo's avatar
rjsmelo committed
89 90 91 92 93 94 95
	/**
	 * @param $prefs
	 * @param $active_pref
	 * @param $config_pref
	 * @return array
	 */
	private function get_map($prefs, $active_pref, $config_pref)
96
	{
rjsmelo's avatar
rjsmelo committed
97
		if (! $prefs) {
98 99 100
			global $prefs;
		}

rjsmelo's avatar
rjsmelo committed
101
		$out = [];
102

rjsmelo's avatar
rjsmelo committed
103 104
		if (( ! empty($prefs[$active_pref]) && $prefs[$active_pref] != 'n' ) && isset($prefs[$config_pref])) {
			foreach (explode("\n", $prefs[$config_pref]) as $config) {
105 106 107 108
				if (substr_count($config, ',') == 1) {
					// Ignore lines which don't have exactly one comma, such as empty lines.
					// TODO: make sure there are no such lines in the first place
					list($domain, $perspective) = explode(',', $config);
109 110
					$out[$domain] = trim($perspective);
				}
111
			}
112 113 114 115 116
		}

		return $out;
	}

rjsmelo's avatar
rjsmelo committed
117 118 119 120 121
	/**
	 * @param null $prefs
	 * @return array
	 */
	function get_subnet_map($prefs = null)
122
	{
123 124 125
		return $this->get_map($prefs, 'site_terminal_active', 'site_terminal_config');
	}

rjsmelo's avatar
rjsmelo committed
126 127 128 129 130
	/**
	 * @param null $prefs
	 * @return array
	 */
	function get_domain_map($prefs = null)
131
	{
132 133 134
		return $this->get_map($prefs, 'multidomain_active', 'multidomain_config');
	}

rjsmelo's avatar
rjsmelo committed
135 136 137 138 139 140
	/**
	 * @param $ip
	 * @param $subnet
	 * @return bool
	 */
	private function is_in_subnet($ip, $subnet)
141 142
	{
		list($subnet, $size) = explode('/', $subnet);
143 144 145 146

		// Warning - bit shifting ahead.

		// Create the real mask from the /X suffix
147
		$mask = 0xFFFFFFFF ^ ((1 << (int) (32 - $size)) - 1);
148 149 150 151 152

		// Make sure the subnet-relevant part matches for the IP and the subnet being compared
		return (ip2long($subnet) & $mask) === (ip2long($ip) & $mask);
	}

153 154 155 156
	/**
	 * Returns a string-indexed array containing the preferences for the given perspective as "pref_name" => "pref_value".
	 *
	 */
rjsmelo's avatar
rjsmelo committed
157
	function get_preferences($perspectiveId)
158
	{
rjsmelo's avatar
rjsmelo committed
159
		$result = TikiDb::get()->query("SELECT pref, value FROM tiki_perspective_preferences WHERE perspectiveId = ?", [ $perspectiveId ]);
160

rjsmelo's avatar
rjsmelo committed
161
		$out = [];
162

rjsmelo's avatar
rjsmelo committed
163
		while ($row = $result->fetchRow()) {
164
			$out[ $row['pref'] ] = unserialize($row['value']);
165 166 167 168 169
		}

		return $out;
	}

170 171 172 173 174 175 176 177 178 179 180 181 182 183
	function load_perspective_preferences()
	{
		global $prefs, $section;

		if (! isset($section) || $section != 'admin') {
			if ($persp = $this->get_current_perspective($prefs)) {
				$perspectivePreferences = $this->get_preferences($persp);
				$prefs = $perspectivePreferences + $prefs;
			}
		}

		return $prefs;
	}

rjsmelo's avatar
rjsmelo committed
184 185 186 187 188
	/**
	 * @param $perspectiveId
	 * @return mixed
	 */
	function get_perspective($perspectiveId)
189
	{
rjsmelo's avatar
rjsmelo committed
190
		$result = TikiDb::get()->query("SELECT perspectiveId, name FROM tiki_perspectives WHERE perspectiveId = ?", [ $perspectiveId ]);
191

rjsmelo's avatar
rjsmelo committed
192 193 194
		if ($info = $result->fetchRow()) {
			$perms = Perms::get([ 'type' => 'perspective', 'object' => $perspectiveId ]);
			if ($perms->perspective_view) {
195 196
				$info['preferences'] = $this->get_preferences($perspectiveId);
				$this->write_permissions($info, $perms);
197 198 199 200 201 202

				return $info;
			}
		}
	}

oeversetten's avatar
oeversetten committed
203

204 205 206 207 208 209
	/**
	 * Changes the current perspective and redirects if multidomain_switchdomain enabled
	 *
	 * @param int $perspective	perspective id
	 * @param bool $by_area		switched by the "areas" feature according to content, so keeps the same REQUEST_URI
	 */
rjsmelo's avatar
rjsmelo committed
210
	function set_perspective($perspective, $by_area = false)
211
	{
212 213 214
		global $prefs, $url_scheme, $user, $tikiroot;

		$preferred_perspective = $this->get_preferred_perspective($user);
215

rjsmelo's avatar
rjsmelo committed
216
		if ($this->get_perspective($perspective) || empty($perspective)) {
217
			if ($prefs['multidomain_switchdomain'] == 'y') {
218 219 220
				foreach ($this->get_domain_map() as $domain => $persp) {
					if ($persp == $perspective && isset($_SERVER['HTTP_HOST']) && $domain != $_SERVER['HTTP_HOST']) {
						$path = $tikiroot;
rjsmelo's avatar
rjsmelo committed
221
						if ($by_area && ! empty($_SERVER['REQUEST_URI'])) {
222
							$path = $_SERVER['REQUEST_URI'];
223 224
						}
						$targetUrl = $url_scheme . '://' . $domain . $path;
oeversetten's avatar
oeversetten committed
225

226 227 228
						if ($prefs['feature_areas'] === 'y') {
							header('HTTP/1.0 301 Found');
						}
229 230 231
						header('Location: ' . $targetUrl);
						exit;
					}
oeversetten's avatar
oeversetten committed
232 233
				}
			}
234
		}
235
		if (empty($perspective) && !$preferred_perspective) {
236
			unset($_SESSION['current_perspective']);
237
			unset($_SESSION['current_perspective_name']);
238
		} else {
239
			$_SESSION['current_perspective'] = $perspective;
240
			$_SESSION['current_perspective_name'] = $this->get_perspective_name($_SESSION['current_perspective']);
oeversetten's avatar
oeversetten committed
241
		}
242
	}
oeversetten's avatar
oeversetten committed
243 244


rjsmelo's avatar
rjsmelo committed
245 246 247 248 249
	/**
	 * @param $info
	 * @param $perms
	 */
	private function write_permissions(& $info, $perms)
250
	{
251 252 253 254 255
		$info['can_edit'] = $perms->perspective_edit;
		$info['can_remove'] = $perms->perspective_admin;
		$info['can_perms'] = $perms->perspective_admin;
	}

256 257 258 259 260 261
	/**
	 * Adds or renames a perspective. If $perspectiveId exists, rename it to $name.
	 * Otherwise, create a new perspective with id $perspectiveId named $name.
	 * Returns true if and only if the operation succeeds.
	 *
	 */
rjsmelo's avatar
rjsmelo committed
262
	function replace_perspective($perspectiveId, $name)
263
	{
rjsmelo's avatar
rjsmelo committed
264
		if ($perspectiveId) {
265
			$this->perspectives->update(
rjsmelo's avatar
rjsmelo committed
266 267
				['name' => $name,],
				['perspectiveId' => $perspectiveId,]
268
			);
269 270 271

			return $perspectiveId;
		} else {
rjsmelo's avatar
rjsmelo committed
272
			return $this->perspectives->insert(['name' => $name,]);
273 274
		}
	}
275 276 277 278 279

	/**
	 * Removes a perspective
	 *
	 */
rjsmelo's avatar
rjsmelo committed
280
	function remove_perspective($perspectiveId)
281
	{
rjsmelo's avatar
rjsmelo committed
282 283 284
		if ($perspectiveId) {
			$this->perspectives->delete(['perspectiveId' => $perspectiveId]);
			$this->perspectivePreferences->deleteMultiple(['perspectiveId' => $perspectiveId]);
285 286
		}
	}
287

288 289 290 291 292
	/**
	 * Replaces all preferences from $perspectiveId with those in the provided string-indexed
	 *   array (in format "pref_name" => "pref_value").
	 *
	 */
rjsmelo's avatar
rjsmelo committed
293
	function replace_preferences($perspectiveId, $preferences)
294
	{
rjsmelo's avatar
rjsmelo committed
295
		$this->perspectivePreferences->deleteMultiple(['perspectiveId' => $perspectiveId]);
296

297
		$prefslib = TikiLib::lib('prefs');
rjsmelo's avatar
rjsmelo committed
298 299
		foreach ($preferences as $pref => $value) {
			$value = $prefslib->formatPreference($pref, [$pref => $value]);
300
			$this->set_preference($perspectiveId, $pref, $value);
301 302
		}
	}
303 304 305 306 307

	/**
	 * Replaces a specific preference
	 *
	 */
rjsmelo's avatar
rjsmelo committed
308
	function replace_preference($preference, $value, $newValue)
309 310
	{
		$this->perspectivePreferences->update(
rjsmelo's avatar
rjsmelo committed
311 312
			['value' => serialize($newValue),],
			[
313 314
				'pref' => $preference,
				'value' => serialize($value),
rjsmelo's avatar
rjsmelo committed
315
			]
316 317 318 319 320 321 322
		);
	}

	/**
	 * Sets $preference's value for $perspectiveId to $value
	 *
	 */
rjsmelo's avatar
rjsmelo committed
323
	function set_preference($perspectiveId, $preference, $value)
324 325
	{
		$this->perspectivePreferences->delete(
rjsmelo's avatar
rjsmelo committed
326
			[
327 328
				'perspectiveId' => $perspectiveId,
				'pref' => $preference,
rjsmelo's avatar
rjsmelo committed
329
			]
330 331 332
		);

		$this->perspectivePreferences->insert(
rjsmelo's avatar
rjsmelo committed
333
			[
334 335 336
				'perspectiveId' => $perspectiveId,
				'pref' => $preference,
				'value' => serialize($value),
rjsmelo's avatar
rjsmelo committed
337
			]
338 339 340 341 342 343 344
		);
	}

	/**
	 * Returns true if and only if a perspective with the given $perspectiveId exists
	 *
	 */
rjsmelo's avatar
rjsmelo committed
345
	function perspective_exists($perspectiveId)
346
	{
347 348
		$db = TikiDb::get();

349
		$id = $db->getOne(
350
			'SELECT perspectiveId FROM tiki_perspectives WHERE perspectiveId = ?',
rjsmelo's avatar
rjsmelo committed
351
			[ $perspectiveId ]
352 353
		);

rjsmelo's avatar
rjsmelo committed
354
		return ! empty($id);
355
	}
356

rjsmelo's avatar
rjsmelo committed
357 358 359 360 361 362
	/**
	 * @param int $offset
	 * @param $maxRecords
	 * @return array
	 */
	function list_perspectives($offset = 0, $maxRecords = -1)
363
	{
364 365
		$db = TikiDb::get();

rjsmelo's avatar
rjsmelo committed
366
		$list = $db->fetchAll("SELECT perspectiveId, name FROM tiki_perspectives", [], $maxRecords, $offset);
367

368
		$list = Perms::simpleFilter('perspective', 'perspectiveId', 'perspective_view', $list);
369

rjsmelo's avatar
rjsmelo committed
370 371
		foreach ($list as & $info) {
			$perms = Perms::get([ 'type' => 'perspective', 'object' => $info['perspectiveId'] ]);
372
			$this->write_permissions($info, $perms);
373 374
		}

375
		return $list;
376
	}
377

378 379 380 381
	/**
	 * Returns one of the perspectives with the given name
	 *
	 */
rjsmelo's avatar
rjsmelo committed
382
	function get_perspective_with_given_name($name)
383 384
	{
		$db = TikiDb::get();
385

rjsmelo's avatar
rjsmelo committed
386
		return $db->getOne("SELECT perspectiveId FROM tiki_perspectives WHERE name = ?", [ $name ]);
387
	}
388 389 390 391 392

	/**
	 * Returns perspective's name from the Id
	 *
	 */
rjsmelo's avatar
rjsmelo committed
393
	function get_perspective_name($id)
394 395 396
	{
		$db = TikiDb::get();

rjsmelo's avatar
rjsmelo committed
397
		return $db->getOne("SELECT name FROM tiki_perspectives WHERE perspectiveId = ?", [ $id ]);
398
	}
399
}