/** * 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; } } } } }
public function import() { $id = isset(\IPS\Request::i()->id) ? intval(\IPS\Request::i()->id) : 0; /* Build form */ $form = new \IPS\Helpers\Form(NULL, 'import'); if (isset(\IPS\Request::i()->id)) { $group = \IPS\membermap\Markers\Groups::load(intval(\IPS\Request::i()->id)); if ($group->type == 'member') { \IPS\Output::i()->error('generic_error', '1MM4/1', 403, ''); } } $form->add(new \IPS\Helpers\Form\Upload('import_upload', NULL, TRUE, array('allowedFileTypes' => array('kml'), 'temporary' => TRUE))); $form->add(new \IPS\Helpers\Form\YesNo('import_creategroups', FALSE, FALSE, array('togglesOff' => array('import_group')))); $form->add(new \IPS\Helpers\Form\Node('import_group', $id ?: 0, FALSE, array('class' => '\\IPS\\membermap\\Markers\\Groups', 'permissionCheck' => 'add', 'subnodes' => false, 'where' => array('group_type != ?', 'member')), NULL, NULL, NULL, 'import_group')); if ($values = $form->values()) { try { $xml = \IPS\Xml\SimpleXML::loadFile($values['import_upload']); } catch (\InvalidArgumentException $e) { $form->error = \IPS\Member::loggedIn()->language()->addToStack('xml_upload_invalid'); \IPS\Output::i()->output = $form; return; } /* No group selected, and don't create groups?! */ if ($values['import_creategroups'] == FALSE and !$values['import_group']) { $form->error = \IPS\Member::loggedIn()->language()->addToStack('membermap_error_no_id_no_create'); \IPS\Output::i()->output = $form; return; } $markers = array(); $groupOrder = NULL; $imported = 0; foreach ($xml->Document->Folder as $folder) { if (!isset($folder->Placemark)) { continue; } $folderName = (string) $folder->name; foreach ($folder->Placemark as $placemark) { if (!isset($placemark->Point->coordinates)) { continue; } list($lon, $lat, $elev) = explode(',', $placemark->Point->coordinates); $markers[] = array('marker_name' => (string) $placemark->name, 'marker_name_seo' => \IPS\Http\Url::seoTitle((string) $placemark->name), 'marker_description' => (string) $placemark->description, 'marker_lat' => $lat, 'marker_lon' => $lon, 'marker_member_id' => \IPS\Member::loggedIn()->member_id, 'marker_added' => time(), 'marker_open' => 1, 'marker_parent_id' => isset($values['import_group']) ? $values['import_group']->id : NULL); } /* Create a new group per "folder" */ if ($values['import_creategroups'] == TRUE and count($markers) > 0) { if ($groupOrder === NULL) { $groupOrder = \IPS\Db::i()->select(array("MAX( `group_position` ) as position"), 'membermap_markers_groups')->first(); } $groupOrder = $groupOrder + 1; $group = new \IPS\membermap\Markers\Groups(); $group->name = $folderName; $group->name_seo = \IPS\Http\Url::seoTitle($folderName); $group->type = 'custom'; $group->pin_colour = '#FFFFFF'; $group->pin_bg_colour = 'red'; $group->pin_icon = 'fa-globe'; $group->position = $groupOrder; $group->save(); \IPS\Lang::saveCustom('membermap', "membermap_marker_group_{$group->id}", trim($folderName)); \IPS\Lang::saveCustom('membermap', "membermap_marker_group_{$group->id}_JS", trim($folderName), 1); // Add group id to all elements of the array array_walk($markers, function (&$v, $k) use($group) { $v['marker_parent_id'] = $group->id; }); // Insert \IPS\Db::i()->insert('membermap_markers', $markers); $group->setLastComment(); $group->save(); // Set default permissions $perms = $group->permissions(); \IPS\Db::i()->update('core_permission_index', array('perm_view' => '*', 'perm_2' => '*', 'perm_3' => \IPS\Settings::i()->admin_group, 'perm_4' => \IPS\Settings::i()->admin_group), array('perm_id=?', $perms['perm_id'])); // Reset $imported += count($markers); $markers = array(); } } /* If we still got markers here, it's all pushed to one group, probably */ if (is_array($markers) and count($markers) > 0) { \IPS\Db::i()->insert('membermap_markers', $markers); $group = $values['import_group']; $group->setLastComment(); $group->save(); $imported += count($markers); } \IPS\membermap\Map::i()->invalidateJsonCache(); $message = \IPS\Member::loggedIn()->language()->addToStack('membermap_import_thumbup', FALSE, array('sprintf' => array($imported))); \IPS\Output::i()->redirect(\IPS\Http\Url::internal("app=membermap&module=membermap&controller=markers"), $message); } /* Display */ \IPS\Output::i()->output = $form; }
/** * Loads add/update location form * * @return void */ protected function add() { if (!\IPS\Member::loggedIn()->member_id) { \IPS\Output::i()->error('no_permission', '2MM3/1', 403, ''); } /* Get the members location, if it exists */ $existing = \IPS\membermap\Map::i()->getMarkerByMember(\IPS\Member::loggedIn()->member_id, FALSE); $groupId = \IPS\membermap\Map::i()->getMemberGroupId(); /* Check permissions */ if ($existing) { if (!$existing->canEdit()) { \IPS\Output::i()->error('membermap_error_cantEdit', '2MM3/2', 403, ''); } } else { if (!\IPS\membermap\Markers\Groups::load($groupId)->can('add')) { \IPS\Output::i()->error('membermap_error_cantAdd', '2MM3/3', 403, ''); } } /* HTML5 GeoLocation form */ $geoLocForm = new \IPS\Helpers\Form('membermap_form_geoLocation', NULL, NULL, array('id' => 'membermap_form_geoLocation')); $geoLocForm->class = 'ipsForm_vertical ipsType_center'; $geoLocForm->addHeader('membermap_current_location'); $geoLocForm->addHtml('<li class="ipsType_center"><i class="fa fa-fw fa-4x fa-location-arrow"></i></li>'); $geoLocForm->addHtml('<li class="ipsType_center">' . \IPS\Member::loggedIn()->language()->addToStack('membermap_geolocation_desc') . '</li>'); $geoLocForm->addButton('membermap_current_location', 'button', NULL, 'ipsButton ipsButton_primary', array('id' => 'membermap_currentLocation')); $form = new \IPS\Helpers\Form('membermap_form_location', NULL, NULL, array('id' => 'membermap_form_location')); $form->class = 'ipsForm_vertical ipsType_center'; $form->addHeader('membermap_form_location'); $form->add(new \IPS\Helpers\Form\Text('membermap_location', '', FALSE, array('placeholder' => \IPS\Member::loggedIn()->language()->addToStack('membermap_form_placeholder')), NULL, NULL, NULL, 'membermap_location')); $form->addButton('save', 'submit', NULL, 'ipsPos_center ipsButton ipsButton_primary', array('id' => 'membermap_locationSubmit')); $form->hiddenValues['lat'] = \IPS\Request::i()->lat; $form->hiddenValues['lng'] = \IPS\Request::i()->lng; if ($values = $form->values()) { try { /* Create marker */ if ($existing instanceof \IPS\membermap\Markers\Markers) { $marker = $existing; $marker->updated = time(); } else { $marker = \IPS\membermap\Markers\Markers::createItem(\IPS\Member::loggedIn(), \IPS\Request::i()->ipAddress(), new \IPS\DateTime(), \IPS\membermap\Markers\Groups::load($groupId)); $marker->member_id = \IPS\Member::loggedIn()->member_id; } if (isset($values['membermap_location']) and !empty($values['membermap_location'])) { $marker->location = $values['membermap_location']; } $marker->name = \IPS\Member::loggedIn()->name; $marker->lat = $values['lat']; $marker->lon = $values['lng']; $marker->save(); /* Add to search index */ \IPS\Content\Search\Index::i()->index($marker); /* Content approval is requred, redirect the member to the marker page, where this is made clear */ if ($marker->hidden()) { \IPS\Output::i()->redirect($marker->url()); } else { \IPS\Output::i()->redirect(\IPS\Http\Url::internal('app=membermap&module=membermap&controller=showmap&dropBrowserCache=1&goHome=1', 'front', 'membermap')); } return; } catch (\Exception $e) { $form->error = \IPS\Member::loggedIn()->language()->addToStack('membermap_' . $e->getMessage()); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('map')->addLocation($geoLocForm, $form); return; } } \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack(!$existing ? 'membermap_button_addLocation' : 'membermap_button_editLocation'); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('map')->addLocation($geoLocForm, $form); }
/** * 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; }