/** * Load and extract our application development files * * @return void */ public static function extract() { /* Are we IN_DEV (and does it matter)? */ if (static::$checkInDev) { if (!defined('\\IPS\\IN_DEV') or !\IPS\IN_DEV) { return; } } /* Attempt to load our application */ $thisApp = NULL; $applications = \IPS\Application::applications(); foreach ($applications as $application) { if ($application->directory === static::$appDir) { $thisApp = $application; } } if (!$thisApp) { \IPS\Log::i(\LOG_ERR)->write('Error : Application ' . static::$appDir . ' not found', 'devpackager_error'); return; } /* Set our paths */ $appPath = join(\DIRECTORY_SEPARATOR, [\IPS\ROOT_PATH, 'applications', $thisApp->directory]); $devPath = join(\DIRECTORY_SEPARATOR, [$appPath, 'dev']); $devTar = join(\DIRECTORY_SEPARATOR, [$appPath, 'data', 'dev.tar']); /* Load and extract our tarball */ try { if (!is_dir($devPath)) { mkdir($devPath, 0777, true); } $devFiles = new \PharData($devTar, 0, NULL, \Phar::TAR); $devFiles->extractTo($devPath, NULL, TRUE); } catch (\Exception $e) { \IPS\Log::i(\LOG_ERR)->write('Error : ' . $e->getMessage() . "\n" . $e->getTraceAsString(), 'devpackager_error'); } }
/** * Member account has been updated * * @param $member \IPS\Member Member updating profile * @param $changes array The changes * @return void */ public function onProfileUpdate($member, $changes) { /* An endless loop is formed when \Item::createItem() is saving \Member, which then fire this membersync, which then calls \Item::createItem, and so on, and so on */ static $wereDoneHere = false; if ($wereDoneHere) { return; } $wereDoneHere = true; if (isset($changes['name'])) { $existingMarker = \IPS\membermap\Map::i()->getMarkerByMember($member->member_id, FALSE, FALSE); if ($existingMarker instanceof \IPS\membermap\Markers\Markers) { $existingMarker->name = $member->name; $existingMarker->updated = time(); $existingMarker->save(); } } if (count($changes) and \IPS\Settings::i()->membermap_monitorLocationField and !$member->members_bitoptions['bw_is_spammer']) { if (\IPS\Settings::i()->membermap_monitorLocationField_groupPerm === '*' or \IPS\Member::loggedIn()->inGroup(explode(',', \IPS\Settings::i()->membermap_monitorLocationField_groupPerm))) { if (isset($changes['field_' . \IPS\Settings::i()->membermap_profileLocationField]) and !empty($changes['field_' . \IPS\Settings::i()->membermap_profileLocationField])) { try { $lat = $lng = $location = NULL; $fieldValue = $changes['field_' . \IPS\Settings::i()->membermap_profileLocationField]; /* If it's an array, it might be from an address field, which already have the lat/lng data */ if (is_array(json_decode($fieldValue, TRUE))) { $addressData = json_decode($fieldValue, TRUE); if (is_float($addressData['lat']) and is_float($addressData['long'])) { $lat = floatval($addressData['lat']); $lng = floatval($addressData['long']); } $addressData['addressLines'][] = $addressData['city']; if (count($addressData['addressLines'])) { $location = implode(', ', $addressData['addressLines']); } } else { /* Remove HTML, newlines, tab, etc, etc */ $fieldValue = preg_replace("/[\\x00-\\x20]|\\xc2|\\xa0+/", ' ', strip_tags($fieldValue)); $fieldValue = trim(preg_replace("/\\s\\s+/", ' ', $fieldValue)); /* To my understanding we're not allowed to use \IPS\Geolocation, as that uses Google API, and we're not showing the info on a Google Map. */ $nominatim = \IPS\membermap\Map::i()->getLatLng($fieldValue); if (is_array($nominatim) and count($nominatim)) { $lat = $nominatim['lat']; $lng = $nominatim['lng']; $location = $nominatim['location']; } } if ($lat and $lng) { $existingMarker = \IPS\membermap\Map::i()->getMarkerByMember($member->member_id, FALSE); if ($existingMarker instanceof \IPS\membermap\Markers\Markers) { $marker = $existingMarker; $marker->updated = time(); } else { $groupId = \IPS\membermap\Map::i()->getMemberGroupId(); $marker = \IPS\membermap\Markers\Markers::createItem($member, \IPS\Request::i()->ipAddress(), new \IPS\DateTime(), \IPS\membermap\Markers\Groups::load($groupId)); } $marker->name = $member->name; $marker->lat = $lat; $marker->lon = $lng; $marker->location = $location ?: $fieldValue; /* Save and add to search index */ $marker->save(); \IPS\Content\Search\Index::i()->index($marker); } } catch (\Exception $e) { /* Something went wrong. Such as the input field being an editor */ \IPS\Log::log($e, 'membermap'); return false; } } } } }
/** * Geocode, get lat/lng by location * * @param string Location * @return array Lat/lng/formatted address */ public function getLatLng($location) { static $locCache = array(); $locKey = md5($location); if (isset($locCache['cache-' . $locKey])) { return $locCache['cache-' . $locKey]; } $apiKey = \IPS\membermap\Application::getApiKeys('mapquest'); if ($apiKey) { try { $data = \IPS\Http\Url::external("https://open.mapquestapi.com/nominatim/v1/search.php?key={$apiKey}&format=json&limit=1&q=" . urlencode($location))->request(15)->get()->decodeJson(); if (is_array($data) and count($data)) { $locCache['cache-' . $locKey] = array('lat' => $data[0]['lat'], 'lng' => $data[0]['lon'], 'location' => $data[0]['display_name']); return $locCache['cache-' . $locKey]; } else { /* No result for this */ $locCache['cache-' . $locKey] = false; } } catch (\RuntimeException $e) { \IPS\Log::log($e, 'membermap'); return false; } } return false; }
/** * Execute * * If ran successfully, should return anything worth logging. Only log something * worth mentioning (don't log "task ran successfully"). Return NULL (actual NULL, not '' or 0) to not log (which will be most cases). * If an error occurs which means the task could not finish running, throw an \IPS\Task\Exception - do not log an error as a normal log. * Tasks should execute within the time of a normal HTTP request. * * @return mixed Message to log or NULL * @throws \IPS\Task\Exception */ public function execute() { if (!\IPS\Settings::i()->membermap_syncLocationField or !\IPS\Settings::i()->membermap_monitorLocationField or !\IPS\Settings::i()->membermap_profileLocationField) { $this->enabled = FALSE; $this->save(); return; } $fieldKey = \IPS\Settings::i()->membermap_profileLocationField; $limit = 100; $counter = 0; $memberMarkerGroupId = \IPS\membermap\Map::i()->getMemberGroupId(); try { $where = array(); $where[] = array("( pf.field_{$fieldKey} IS NOT NULL OR pf.field_{$fieldKey} != '' )"); $where[] = array("mm.marker_id IS NULL"); $where[] = array("m.membermap_location_synced = 0"); $where[] = array('( ! ' . \IPS\Db::i()->bitwiseWhere(\IPS\Member::$bitOptions['members_bitoptions'], 'bw_is_spammer') . ' )'); if (\IPS\Settings::i()->membermap_monitorLocationField_groupPerm !== '*') { $where[] = \IPS\Db::i()->in('m.member_group_id', explode(',', \IPS\Settings::i()->membermap_monitorLocationField_groupPerm)); } $members = \IPS\Db::i()->select('*', array('core_members', 'm'), $where, 'm.last_activity DESC', array(0, $limit))->join(array('core_pfields_content', 'pf'), 'pf.member_id=m.member_id')->join(array('membermap_markers', 'mm'), 'mm.marker_member_id=m.member_id AND mm.marker_parent_id=' . $memberMarkerGroupId); foreach ($members as $member) { $lat = $lng = $location = NULL; $_member = \IPS\Member::constructFromData($member); /* Need to set this to prevent us from looping over the same members with invalid locations over and over again */ $_member->membermap_location_synced = 1; $_member->save(); $_location = trim($member['field_' . $fieldKey]); if (empty($_location)) { continue; } /* If it's an array, it might be from an address field, which already have the lat/lng data */ if (is_array(json_decode($_location, TRUE))) { $addressData = json_decode($_location, TRUE); if (is_float($addressData['lat']) and is_float($addressData['long'])) { $lat = floatval($addressData['lat']); $lng = floatval($addressData['long']); } $addressData['addressLines'][] = $addressData['city']; if (count($addressData['addressLines'])) { $location = implode(', ', $addressData['addressLines']); } } else { /* Remove HTML, newlines, tab, etc, etc */ $_location = preg_replace("/[\\x00-\\x20]|\\xc2|\\xa0+/", ' ', strip_tags($_location)); $_location = trim(preg_replace("/\\s\\s+/", ' ', $_location)); /* To my understanding we're not allowed to use \IPS\Geolocation, as that uses Google API, and we're not showing the info on a Google Map. */ $nominatim = \IPS\membermap\Map::i()->getLatLng($_location); if (is_array($nominatim) and count($nominatim)) { $lat = $nominatim['lat']; $lng = $nominatim['lng']; $location = $nominatim['location']; } } if ($lat and $lng) { $marker = \IPS\membermap\Markers\Markers::createItem($_member, NULL, new \IPS\DateTime(), \IPS\membermap\Markers\Groups::load($memberMarkerGroupId), FALSE); $marker->name = $_member->name; $marker->lat = $lat; $marker->lon = $lng; $marker->location = $location ?: $_location; $marker->save(); /* Add to index */ \IPS\Content\Search\Index::i()->index($marker); $counter++; } } } catch (\UnderflowException $e) { } catch (\RuntimeException $e) { \IPS\Log::log(array($e->getMessage(), $nominatim), 'membermap'); } catch (\Exception $e) { \IPS\Log::log(array($e->getMessage(), $nominatim), 'membermap'); throw new \IPS\Task\Exception($this, $e->getMessage()); } if ($counter > 0) { $foundRows = $members->count(); return "Synchronised {$counter} out of {$foundRows} member locations"; } else { $this->enabled = FALSE; $this->save(); /* Turn the setting off as well */ \IPS\Db::i()->update('core_sys_conf_settings', array('conf_value' => 0), array('conf_key=?', 'membermap_syncLocationField')); unset(\IPS\Data\Store::i()->settings); return; } return NULL; }