Show:

File: platform/plugins/Places/handlers/Places/geolocation/post.php

<?php

/**
 * @module Places
 */

/**
 * Used to set the user's location from geolocation data.
 * @class HTTP Places geolocation
 * @method post
 * @param $_REQUEST
 * @param {double} [$_REQUEST.latitude] The new latitude. If set, must also specify longitude.
 * @param {double} [$_REQUEST.longitude] The new longitude. If set, must also specify latitude.
 * @param {string} [$_REQUEST.postcode] The new zip code. Can be set instead of latitude, longitude.
 * @param {double} [$_REQUEST.meters] The distance around their location around that the user is interested in
 * @param {Number} [$_REQUEST.joinNearby=0] Pass 1 to join to the Places/nearby stream at the new location. Pass 2 to join and subscribe.
 * @param {Number} [$_REQUEST.leaveNearby=0] Pass 1 to unsubscribe from the Places/nearby stream at the old location. Pass 2 to unsubscribe and leave.
 * @param {Number} [$_REQUEST.joinInterests=0] Pass 1 to join to all the local interests at the new location. Pass 2 to join and subscribe.
 * @param {Number} [$_REQUEST.leaveInterests=0] Whether to unsubscribe from all the local interests at the old location. Pass 2 to unsubscribe and leave.
 * @param {double} [$_REQUEST.accuracy]
 * @param {double} [$_REQUEST.altitude]
 * @param {double} [$_REQUEST.altitudeAccuracy]
 * @param {double} [$_REQUEST.heading]
 * @param {double} [$_REQUEST.speed]
 * @param {integer} [$_REQUEST.timezone]
 * @param {string} [$_REQUEST.placeName] optional
 * @param {string} [$_REQUEST.state] optional
 * @param {string} [$_REQUEST.country] optional
 */
function Places_geolocation_post()
{
	$user = Users::loggedInUser(true);
	$stream = Places_Location::userStream();
	$oldLatitude = $stream->getAttribute('latitude');
	$oldLongitude = $stream->getAttribute('longitude');
	$oldMeters = $stream->getAttribute('meters');
	$fields = array(
		'accuracy',
		'altitude',
		'altitudeAccuracy',
		'heading',
		'latitude',
		'longitude',
		'speed',
		'meters',
		'postcode',
		'timezone',
		'placeName',
		'state',
		'country'
	);
	$attributes = Q::take($_REQUEST, $fields);
	if (isset($attributes['timezone'])) {
		$attributes['timezone'] = floatval($attributes['timezone']);
	}
	if (isset($attributes['latitude'])
	xor isset($attributes['longitude'])) {
		throw new Q_Exception(
			"When specifying latitude,longitude you must specify both",
			array('latitude', 'longitude')
		);
	}
	if (!empty($attributes['postcode']) and !isset($attributes['latitude'])) {
		$z = new Places_Postcode();
		$z->countryCode = 'US';
		$z->postcode = $attributes['postcode'];
		if ($z->retrieve()) {
			$attributes['latitude'] = $z->latitude;
			$attributes['longitude'] = $z->longitude;
			$attributes['country'] = $z->countryCode;
		} else {
			throw new Q_Exception_MissingRow(array(
				'table' => 'postcode',
				'criteria' => $attributes['postcode']
			), 'postcode');
		}
	}
	$attributes['meters'] = floatval(Q::ifset($attributes, 'meters', 
		$stream->getAttribute(
			'meters',
			Q_Config::expect('Places', 'nearby', 'defaultMeters')
		)
	));
	if (empty($attributes['postcode']) and isset($attributes['latitude'])) {
		$postcodes = Places_Postcode::nearby(
			floatval($attributes['latitude']),
			floatval($attributes['longitude']),
			floatval($attributes['meters']),
			1
		);
		if ($postcode = $postcodes ? reset($postcodes) : null) {
			$attributes['postcode'] = $postcode->postcode;
			$attributes['placeName'] = $postcode->placeName;
			$attributes['state'] = $postcode->state;
			$attributes['country'] = $postcode->countryCode;
		}
	}
	$stream->setAttribute($attributes);
	$stream->changed();
	$stream->post($user->id, array(
		'type' => 'Places/location/updated',
		'content' => '',
		'instructions' => $stream->getAllAttributes()
	), true);
	
	$leaveNearby = isset($oldMeters) ? Q::ifset($_REQUEST, 'leaveNearby', 0) : 0;
	$joinNearby = Q::ifset($_REQUEST, 'joinNearby', 0);
	$leaveInterests = isset($oldMeters) ? Q::ifset($_REQUEST, 'leaveInterests', 0) : 0;
	$joinInterests = Q::ifset($_REQUEST, 'joinInterests', 0);
	$noChange = false;

	$latitude = $stream->getAttribute('latitude');
	$longitude = $stream->getAttribute('longitude');
	$meters = $stream->getAttribute('meters');

	if (abs($latitude - $oldLatitude) < 0.0001
	and abs($longitude - $oldLongitude) < 0.0001
	and abs($meters - $oldMeters) < 0.001) {
		$noChange = true;
	}
	
	$attributes['stream'] = $stream;
	Q_Response::setSlot('attributes', $attributes);

	if (!$noChange) {
		// Send the response and keep going.
		// WARN: this potentially ties up the PHP thread for a long time
		$timeLimit = Q_Config::get('Places', 'geolocation', 'timeLimit', 100000);
		ignore_user_abort(true);
		set_time_limit($timeLimit);
		Q_Dispatcher::response(true);
		session_write_close();
		
		if ($leaveInterests or $joinInterests) {
			$myInterests = Streams_Category::getRelatedTo(
				$user->id, 'Streams/user/interests', 'Streams/interests'
			);
			if (!isset($myInterests)) {
				$myInterests = array();
			}
		}

		if ($leaveInterests and $oldLatitude and $oldLongitude and $oldMeters) {
			$results = array();
			foreach ($myInterests as $weight => $info) {
				$publisherId = $info[0];
				if (!isset($results[$publisherId])) {
					$results[$publisherId] = array();
				}
				$results[$publisherId] = array_merge(
					$results[$publisherId], Places_Interest::streams(
						$publisherId, $oldLatitude, $oldLongitude, $info[2], array(
							'meters' => $oldMeters,
							'skipAccess' => true,
							'forSubscribers' => true
						)
					)
				);
			}
			$method = ($leaveInterests == 2) ? 'leave' : 'unsubscribe';
			foreach ($results as $publisherId => $streams) {
				$attributes['leftInterests'][$publisherId] = call_user_func(
					array('Streams', $method),
					$user->id, $publisherId, $streams, array('skipAccess' => true)
				);
			}
		}
		if ($leaveNearby and $oldLatitude and $oldLongitude and $oldMeters) {
			$method = ($leaveNearby == 2) ? 'leave' : 'unsubscribe';
			$attributes['leftNearby'] = call_user_func(
				array('Places_Nearby', $method),
				Users::communityId(), $oldLatitude, $oldLongitude, $oldMeters
			);
		}
	
		if ($joinInterests) {
			$results = array();
			foreach ($myInterests as $weight => $info) {
				$publisherId = $info[0];
				if (!isset($results[$publisherId])) {
					$results[$publisherId] = array();
				}
				$results[$publisherId] = array_merge(
					$results[$publisherId], Places_Interest::streams(
						$publisherId, $latitude, $longitude, $info[2], array(
							'meters' => $meters,
							'skipAccess' => true,
							'forSubscribers' => true
						)
					)
				);
			}
			$method = ($joinInterests == 1) ? 'join' : 'subscribe';
			foreach ($results as $publisherId => $streams) {
				$attributes['joinedInterests'][$publisherId] = call_user_func(
					array('Streams', $method),
					$user->id, $publisherId, $streams, array('skipAccess' => true)
				);
			}
		}
		if ($joinNearby) {
			$method = ($joinNearby == 1) ? 'join' : 'subscribe';
			$attributes['joinedNearby'] = call_user_func(
				array('Places_Nearby', $method),
				Users::communityId(),
				$latitude, $longitude, $meters
			);
		}
	}
	Q::event("Places/geolocation", $attributes, 'after');
}