function Places_after_Streams_interest_add($params) { $location = Places_Location::userStream(); if ($params['subscribe'] and $location and $location->getAttribute('latitude') and $location->getAttribute('longitude') and $location->getAttribute('miles')) { Places_Nearby::subscribe($location->getAttribute('latitude'), $location->getAttribute('longitude'), $location->getAttribute('miles'), $params['publisherId'], array('transform' => array('Places_Interest', '_transform'), 'create' => array('Places_Interest', '_create'), 'title' => $params['title'], 'skipAccess' => true)); } }
function Places_after_Streams_interest_remove($params) { $location = Places_Location::userStream(); if ($location) { $latitude = $location->getAttribute('latitude'); $longitude = $location->getAttribute('longitude'); $miles = $location->getAttribute('miles'); if ($latitude and $longitude and $miles) { Places_Nearby::unsubscribe($latitude, $longitude, $miles, $params['publisherId'], array('transform' => array('Places_Interest', '_transform'), 'title' => $params['title'], 'skipAccess' => true)); } } }
function Places_geolocation_response_data() { $requireLogin = Q_Config::get('Places', 'geolocation', 'requireLogin', false); if (!$requireLogin and isset($_REQUEST['latitude']) and isset($_REQUEST['longitude'])) { if (!Q_Config::get('Places', 'geolocation', 'allowClientQueries', false)) { throw new Q_Exception("Client queries are restricted, as per Places/geolocation/allowClientQueries"); } $latitude = $_REQUEST['latitude']; $longitude = $_REQUEST['longitude']; } else { $user = Users::loggedInUser(true); $stream = Places_Location::userStream(); $latitude = $stream->getAttribute('latitude'); $longitude = $stream->getAttribute('longitude'); $miles = $stream->getAttribute('miles'); } $miles = Q::ifset($_REQUEST, 'miles', Q_Config::expect('Places', 'nearby', 'defaultMiles')); $zipcodes = Places_Zipcode::nearby($latitude, $longitude, $miles, 1); $zipcode = $zipcodes ? reset($zipcodes) : null; $result = array('requested' => compact('latitude', 'longitude'), 'countryCode' => $zipcode->countryCode, 'zipcode' => $zipcode->zipcode, 'placeName' => $zipcode->placeName, 'stateName' => $zipcode->stateName, 'state' => $zipcode->state, 'regionName' => $zipcode->regionName, 'region' => $zipcode->region, 'latitude' => $zipcode->latitude, 'longitude' => $zipcode->longitude); return $result; }
/** * Get autocomplete results * @method autocomplete * @static * @param {string} $input The text (typically typed by a user) to find completions for * @param {boolean} [$throwIfBadValue=false] * Whether to throw Q_Exception if the result contains a bad value * @param {array} [$types=array("establishment")] Can include "establishment", "locality", "sublocality", "postal_code", "country", "administrative_area_level_1", "administrative_area_level_2". Set to true to include all types. * @param {double} [$latitude=userLocation] Override the latitude of the coordinates to search around * @param {double} [$longitude=userLocation] Override the longitude of the coordinates to search around * @param {double} [$miles=25] Override the radius, in miles, to search around * @return {Streams_Stream|null} * @throws {Q_Exception} if a bad value is encountered and $throwIfBadValue is true */ static function autocomplete($input, $throwIfBadValue = false, $types = null, $latitude = null, $longitude = null, $miles = 25) { $supportedTypes = array("establishment", "locality", "sublocality", "postal_code", "country", "administrative_area_level_1", "administrative_area_level_2"); $input = strtolower($input); if (is_string($types)) { $types = explode(',', $types); } else { if ($types === true) { $types = null; } } if ($types) { foreach ($types as $type) { if (!in_array($type, $supportedTypes)) { throw new Q_Exception_BadValue(array('internal' => '$types', 'problem' => "{$type} is not supported")); } } } if (empty($input)) { if ($throwIfBadValue) { throw new Q_Exception_RequiredField(array('field' => 'input')); } return null; } if (!isset($latitude) or !isset($longitude)) { if ($uls = Places_Location::userStream()) { $latitude = $uls->getAttribute('latitude', null); $longitude = $uls->getAttribute('longitude', null); if (!isset($miles)) { $miles = $uls->getAttribute('miles', 25); } } else { // put some defaults $latitude = 40.5806032; $longitude = -73.9755244; $miles = 25; } } $pa = null; if (Q_Config::get('Places', 'cache', 'autocomplete', true)) { $pa = new Places_Autocomplete(); $pa->query = $input; $pa->types = $types ? implode(',', $types) : ''; $pa->latitude = $latitude; $pa->longitude = $longitude; $pa->miles = $miles; if ($pa->retrieve()) { $ut = $pa->updatedTime; if (isset($ut)) { $db = $pa->db(); $ut = $db->fromDateTime($ut); $ct = $db->getCurrentTimestamp(); $cd = Q_Config::get('Places', 'cache', 'duration', 60 * 60 * 24 * 30); if ($ct - $ut < $cd) { // there are cached autocomplete results that are still viable return Q::json_decode($pa->results, true); } } } } $key = Q_Config::expect('Places', 'google', 'keys', 'server'); $location = "{$latitude},{$longitude}"; $radius = ceil(1609.34 * $miles); if ($types === null) { unset($types); } $query = http_build_query(compact('key', 'input', 'types', 'location', 'radius')); $url = "https://maps.googleapis.com/maps/api/place/autocomplete/json?{$query}"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $json = curl_exec($ch); curl_close($ch); $response = json_decode($json, true); if (empty($response['predictions'])) { throw new Q_Exception("Places::autocomplete: Couldn't obtain predictions for {$input}"); } if (!empty($response['error_message'])) { throw new Q_Exception("Places::autocomplete: " . $response['error_message']); } $results = $response['predictions']; if ($pa) { $pa->results = json_encode($results); $pa->save(); } return $results; }
/** * Used to set the user's location from geolocation data. * @param $_REQUEST * @param [$_REQUEST.latitude] The new latitude. If set, must also specify longitude. * @param [$_REQUEST.longitude] The new longitude. If set, must also specify latitude. * @param [$_REQUEST.zipcode] The new zip code. Can be set instead of latitude, longitude. * @param [$_REQUEST.miles] The distance around their location around that the user is interested in * @param [$_REQUEST.subscribe] Whether to subscribe to all the local interests at the new location. * @param [$_REQUEST.unsubscribe] Whether to unsubscribe from all the local interests at the old location. * @param [$_REQUEST.accuracy] * @param [$_REQUEST.altitude] * @param [$_REQUEST.altitudeAccuracy] * @param [$_REQUEST.heading] * @param [$_REQUEST.speed] * @param [$_REQUEST.timezone] * @param [$_REQUEST.placeName] optional * @param [$_REQUEST.state] optional * @param [$_REQUEST.country] optional */ function Places_geolocation_post() { $user = Users::loggedInUser(true); $stream = Places_Location::userStream(); $oldLatitude = $stream->getAttribute('latitude'); $oldLongitude = $stream->getAttribute('longitude'); $oldMiles = $stream->getAttribute('miles'); $fields = array('accuracy', 'altitude', 'altitudeAccuracy', 'heading', 'latitude', 'longitude', 'speed', 'miles', 'zipcode', 'timezone', 'placeName', 'state', 'country'); $attributes = Q::take($_REQUEST, $fields); 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['zipcode']) and !isset($attributes['latitude'])) { $z = new Places_Zipcode(); $z->countryCode = 'US'; $z->zipcode = $attributes['zipcode']; if ($z->retrieve()) { $attributes['latitude'] = $z->latitude; $attributes['longitude'] = $z->longitude; $attributes['country'] = $z->countryCode; } else { throw new Q_Exception_MissingRow(array('table' => 'zipcode', 'criteria' => $attributes['zipcode']), 'zipcode'); } } $attributes['miles'] = Q::ifset($attributes, 'miles', $stream->getAttribute('miles', Q_Config::expect('Places', 'nearby', 'defaultMiles'))); if (empty($attributes['zipcode']) and isset($attributes['latitude'])) { $zipcodes = Places_Zipcode::nearby($attributes['latitude'], $attributes['longitude'], $attributes['miles'], 1); if ($zipcode = $zipcodes ? reset($zipcodes) : null) { $attributes['zipcode'] = $zipcode->zipcode; $attributes['placeName'] = $zipcode->placeName; $attributes['state'] = $zipcode->state; $attributes['country'] = $zipcode->countryCode; } } $stream->setAttribute($attributes); $stream->save(); $stream->post($user->id, array('type' => 'Places/location/updated', 'content' => '', 'instructions' => $stream->getAllAttributes()), true); $shouldUnsubscribe = !empty($_REQUEST['unsubscribe']) && isset($oldMiles); $shouldSubscribe = !empty($_REQUEST['subscribe']); $noChange = false; $latitude = $stream->getAttribute('latitude'); $longitude = $stream->getAttribute('longitude'); $miles = $stream->getAttribute('miles'); if ($shouldUnsubscribe and $shouldSubscribe and abs($latitude - $oldLatitude) < 0.0001 and abs($longitude - $oldLongitude) < 0.0001 and abs($miles - $oldMiles) < 0.001) { $noChange = true; } if (!$noChange) { if ($shouldUnsubscribe or $shouldSubscribe) { $myInterests = Streams_Category::getRelatedTo($user->id, 'Streams/user/interests', 'Streams/interest'); if (!isset($myInterests)) { $myInterests = array(); } } if ($shouldUnsubscribe) { // TODO: implement mass unsubscribe foreach ($myInterests as $weight => $info) { Places_Nearby::unsubscribe($oldLatitude, $oldLongitude, $oldMiles, $info[0], array('transform' => array('Places_Interest', '_transform'), 'title' => $info[2], 'skipAccess' => true)); } $attributes['unsubscribed'] = Places_Nearby::unsubscribe($oldLatitude, $oldLongitude, $oldMiles); } if ($shouldSubscribe) { // TODO: implement mass subscribe foreach ($myInterests as $weight => $info) { Places_Nearby::subscribe($latitude, $longitude, $miles, $info[0], array('transform' => array('Places_Interest', '_transform'), 'create' => array('Places_Interest', '_create'), 'title' => $info[2], 'skipAccess' => true)); } $attributes['subscribed'] = Places_Nearby::subscribe($latitude, $longitude, $miles); } } $attributes['stream'] = $stream; Q_Response::setSlot('attributes', $attributes); Q::event("Places/geolocation", $attributes, 'after'); }
/** * Used to set the user's location from geolocation data. * @class HTTP Places geolocation * @method post * @param $_REQUEST * @param [$_REQUEST.latitude] The new latitude. If set, must also specify longitude. * @param [$_REQUEST.longitude] The new longitude. If set, must also specify latitude. * @param [$_REQUEST.zipcode] The new zip code. Can be set instead of latitude, longitude. * @param [$_REQUEST.miles] The distance around their location around that the user is interested in * @param [$_REQUEST.subscribe] Whether to subscribe to all the local interests at the new location. * @param [$_REQUEST.unsubscribe] Whether to unsubscribe from all the local interests at the old location. * @param [$_REQUEST.accuracy] * @param [$_REQUEST.altitude] * @param [$_REQUEST.altitudeAccuracy] * @param [$_REQUEST.heading] * @param [$_REQUEST.speed] * @param [$_REQUEST.timezone] * @param [$_REQUEST.placeName] optional * @param [$_REQUEST.state] optional * @param [$_REQUEST.country] optional */ function Places_geolocation_post() { $user = Users::loggedInUser(true); $stream = Places_Location::userStream(); $oldLatitude = $stream->getAttribute('latitude'); $oldLongitude = $stream->getAttribute('longitude'); $oldMiles = $stream->getAttribute('miles'); $fields = array('accuracy', 'altitude', 'altitudeAccuracy', 'heading', 'latitude', 'longitude', 'speed', 'miles', 'zipcode', 'timezone', 'placeName', 'state', 'country'); $attributes = Q::take($_REQUEST, $fields); 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['zipcode']) and !isset($attributes['latitude'])) { $z = new Places_Zipcode(); $z->countryCode = 'US'; $z->zipcode = $attributes['zipcode']; if ($z->retrieve()) { $attributes['latitude'] = $z->latitude; $attributes['longitude'] = $z->longitude; $attributes['country'] = $z->countryCode; } else { throw new Q_Exception_MissingRow(array('table' => 'zipcode', 'criteria' => $attributes['zipcode']), 'zipcode'); } } $attributes['miles'] = Q::ifset($attributes, 'miles', $stream->getAttribute('miles', Q_Config::expect('Places', 'nearby', 'defaultMiles'))); if (empty($attributes['zipcode']) and isset($attributes['latitude'])) { $zipcodes = Places_Zipcode::nearby($attributes['latitude'], $attributes['longitude'], $attributes['miles'], 1); if ($zipcode = $zipcodes ? reset($zipcodes) : null) { $attributes['zipcode'] = $zipcode->zipcode; $attributes['placeName'] = $zipcode->placeName; $attributes['state'] = $zipcode->state; $attributes['country'] = $zipcode->countryCode; } } $stream->setAttribute($attributes); $stream->save(); $stream->post($user->id, array('type' => 'Places/location/updated', 'content' => '', 'instructions' => $stream->getAllAttributes()), true); $shouldUnsubscribe = !empty($_REQUEST['unsubscribe']) && isset($oldMiles); $shouldSubscribe = !empty($_REQUEST['subscribe']); $noChange = false; $latitude = $stream->getAttribute('latitude'); $longitude = $stream->getAttribute('longitude'); $miles = $stream->getAttribute('miles'); if ($shouldUnsubscribe and $shouldSubscribe and abs($latitude - $oldLatitude) < 0.0001 and abs($longitude - $oldLongitude) < 0.0001 and abs($miles - $oldMiles) < 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 ($shouldUnsubscribe or $shouldSubscribe) { $myInterests = Streams_Category::getRelatedTo($user->id, 'Streams/user/interests', 'Streams/interests'); if (!isset($myInterests)) { $myInterests = array(); } } if ($shouldUnsubscribe and $oldLatitude and $oldLongitude and $oldMiles) { $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('miles' => $oldMiles, 'skipAccess' => true, 'forSubscribers' => true))); } foreach ($results as $publisherId => $streams) { Streams::unsubscribe($user->id, $publisherId, $streams, array('skipAccess' => true)); } $attributes['unsubscribed'] = Places_Nearby::unsubscribe($oldLatitude, $oldLongitude, $oldMiles); } if ($shouldSubscribe) { $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('miles' => $miles, 'skipAccess' => true, 'forSubscribers' => true))); } foreach ($results as $publisherId => $streams) { Streams::subscribe($user->id, $publisherId, $streams, array('skipAccess' => true)); } $attributes['subscribed'] = Places_Nearby::subscribe($latitude, $longitude, $miles); } } Q::event("Places/geolocation", $attributes, 'after'); }