public static function call(OkapiRequest $request) { # Read the parameters. $langpref = $request->get_parameter('langpref'); if (!$langpref) { $langpref = "en"; } $fields = $request->get_parameter('fields'); if (!$fields) { $fields = "name"; } $only_locally_used = $request->get_parameter('only_locally_used'); if (!$only_locally_used) { $only_locally_used = "false"; } $only_locally_used = $only_locally_used == "true"; # Get the list of attributes and filter the A-codes based on the # parameters. require_once 'attr_helper.inc.php'; $attrdict = AttrHelper::get_attrdict(); $acodes = array(); foreach ($attrdict as $acode => &$attr_ref) { if ($only_locally_used && $attr_ref['internal_id'] === null) { /* Skip. */ continue; } $acodes[] = $acode; } # Retrieve the attribute objects and return the results. if (count($acodes) > 0) { $params = array('acodes' => implode("|", $acodes), 'langpref' => $langpref, 'fields' => $fields); $results = OkapiServiceRunner::call('services/attrs/attributes', new OkapiInternalRequest($request->consumer, $request->token, $params)); } else { $results = new ArrayObject(); } return Okapi::formatted_response($request, $results); }
public static function call() { # This is a hidden page for OKAPI developers. It will list all # attributes defined in this OC installation (and some other stuff). ob_start(); print "Cache Types:\n\n"; foreach (self::get_all_cachetypes() as $id => $name) { print "{$id}: {$name}\n"; } print "\nLog Types:\n\n"; foreach (self::get_all_logtypes() as $id => $name) { print "{$id}: {$name}\n"; } print "\nAttributes:\n\n"; require_once $GLOBALS['rootpath'] . 'okapi/services/attrs/attr_helper.inc.php'; $internal2acode = AttrHelper::get_internal_id_to_acode_mapping(); $dict = self::get_all_atribute_names(); foreach ($dict as $internal_id => $langs) { print $internal_id . ": "; $langkeys = array_keys($langs); sort($langkeys); if (in_array('en', $langkeys)) { print strtoupper($langs['en']); } else { print ">>>> ENGLISH NAME UNSET! <<<<"; } if (isset($internal2acode[$internal_id])) { print " - " . $internal2acode[$internal_id]; } else { print " - >>>> MISSING A-CODE MAPPING <<<<"; } print "\n"; foreach ($langkeys as $langkey) { print " {$langkey}: " . $langs[$langkey] . "\n"; } } print "\nAttribute notices:\n\n"; print "There are three priorities: (!), (-) and ( )\n"; print "(the last one ( ) can be safely ignored)\n\n"; $attrdict = AttrHelper::get_attrdict(); foreach ($dict as $internal_id => $langs) { if (!isset($internal2acode[$internal_id])) { print "(!) Attribute " . $internal_id . " is not mapped to any A-code.\n"; continue; } $acode = $internal2acode[$internal_id]; $attr = $attrdict[$acode]; foreach ($langs as $lang => $value) { if ($lang == 'en') { continue; } if (!isset($attr['names'][$lang])) { print "(-) Attribute {$acode} is missing a name in the '{$lang}' language.\n"; print " Local name: {$value}\n"; print " OKAPI name: >> none <<\n"; continue; } if ($attr['names'][$lang] !== $value) { print "( ) Attribute {$acode} has a different name in the '{$lang}' language\n"; print " Local name: {$value}\n"; print " OKAPI name: " . $attr['names'][$lang] . "\n"; } } } $response = new OkapiHttpResponse(); $response->content_type = "text/plain; charset=utf-8"; $response->body = ob_get_clean(); return $response; }
/** * Generate a GPX file. * * @param OkapiRequest $request * @param integer $flags * @throws BadRequest * @return An array with GPX file content under 'gpx' key */ public static function create_gpx(OkapiRequest $request, $flags = null) { $vars = array(); # Validating arguments. We will also assign some of them to the # $vars variable which we will use later in the GPS template. $cache_codes = $request->get_parameter('cache_codes'); if ($cache_codes === null) { throw new ParamMissing('cache_codes'); } # Issue 106 requires us to allow empty list of cache codes to be passed into this method. # All of the queries below have to be ready for $cache_codes to be empty! $langpref = $request->get_parameter('langpref'); if (!$langpref) { $langpref = "en"; } $langpref .= "|" . Settings::get('SITELANG'); foreach (array('ns_ground', 'ns_gsak', 'ns_ox', 'latest_logs', 'alt_wpts', 'mark_found') as $param) { $val = $request->get_parameter($param); if (!$val) { $val = "false"; } elseif (!in_array($val, array("true", "false"))) { throw new InvalidParam($param); } $vars[$param] = $val == "true"; } if ($vars['latest_logs'] && !$vars['ns_ground']) { throw new BadRequest("In order for 'latest_logs' to work you have to also include 'ns_ground' extensions."); } $tmp = $request->get_parameter('my_notes'); $vars['my_notes'] = array(); if ($tmp && $tmp != 'none') { $tmp = explode('|', $tmp); foreach ($tmp as $elem) { if ($elem == 'none') { /* pass */ } elseif (in_array($elem, array('desc:text', 'gc:personal_note'))) { if (in_array('none', $tmp)) { throw new InvalidParam('my_notes', "You cannot mix 'none' and '{$elem}'"); } if ($request->token == null) { throw new BadRequest("Level 3 Authentication is required to access my_notes data."); } $vars['my_notes'][] = $elem; } else { throw new InvalidParam('my_notes', "Invalid list entry: '{$elem}'"); } } } $images = $request->get_parameter('images'); if (!$images) { $images = 'descrefs:nonspoilers'; } if (!in_array($images, array('none', 'descrefs:thumblinks', 'descrefs:nonspoilers', 'descrefs:all', 'ox:all'))) { throw new InvalidParam('images', "'{$images}'"); } $vars['images'] = $images; $tmp = $request->get_parameter('attrs'); if (!$tmp) { $tmp = 'desc:text'; } $tmp = explode("|", $tmp); $vars['attrs'] = array(); foreach ($tmp as $elem) { if ($elem == 'none') { /* pass */ } elseif (in_array($elem, array('desc:text', 'ox:tags', 'gc:attrs', 'gc_ocde:attrs'))) { if ($elem == 'gc_ocde:attrs' && Settings::get('OC_BRANCH') != 'oc.de') { $vars['attrs'][] = 'gc:attrs'; } else { $vars['attrs'][] = $elem; } } else { throw new InvalidParam('attrs', "Invalid list entry: '{$elem}'"); } } $protection_areas = $request->get_parameter('protection_areas'); if (!$protection_areas || $protection_areas == 'desc:auto') { if (Settings::get('OC_BRANCH') == 'oc.de') { $protection_areas = 'desc:text'; } else { $protection_areas = 'none'; } } if (!in_array($protection_areas, array('none', 'desc:text'))) { throw new InvalidParam('protection_areas', "'{$protection_areas}'"); } $vars['protection_areas'] = $protection_areas; $tmp = $request->get_parameter('trackables'); if (!$tmp) { $tmp = 'none'; } if (!in_array($tmp, array('none', 'desc:list', 'desc:count'))) { throw new InvalidParam('trackables', "'{$tmp}'"); } $vars['trackables'] = $tmp; $tmp = $request->get_parameter('recommendations'); if (!$tmp) { $tmp = 'none'; } if (!in_array($tmp, array('none', 'desc:count'))) { throw new InvalidParam('recommendations', "'{$tmp}'"); } $vars['recommendations'] = $tmp; $lpc = $request->get_parameter('lpc'); if ($lpc === null) { $lpc = 10; } # will be checked in services/caches/geocaches call $user_uuid = $request->get_parameter('user_uuid'); # location_source (part 1 of 2) $location_source = $request->get_parameter('location_source'); if (!$location_source) { $location_source = 'default-coords'; } # Make sure location_source has prefix alt_wpt: if ($location_source != 'default-coords' && strncmp($location_source, 'alt_wpt:', 8) != 0) { throw new InvalidParam('location_source', '\'' . $location_source . '\''); } # Make sure we have sufficient authorization if ($location_source == 'alt_wpt:user-coords' && $request->token == null) { throw new BadRequest("Level 3 Authentication is required to access 'alt_wpt:user-coords'."); } # Which fields of the services/caches/geocaches method do we need? $fields = 'code|name|location|date_created|url|type|status|size|size2|oxsize' . '|difficulty|terrain|description|hint2|rating|owner|url|internal_id' . '|protection_areas|short_description'; if ($vars['images'] != 'none') { $fields .= "|images"; } if (count($vars['attrs']) > 0) { $fields .= "|attrnames|attr_acodes"; } if ($vars['trackables'] == 'desc:list') { $fields .= "|trackables"; } elseif ($vars['trackables'] == 'desc:count') { $fields .= "|trackables_count"; } if ($vars['alt_wpts'] == 'true' || $location_source != 'default-coords') { $fields .= "|alt_wpts"; } if ($vars['recommendations'] != 'none') { $fields .= "|recommendations|founds"; } if (count($vars['my_notes']) > 0) { $fields .= "|my_notes"; } if ($vars['latest_logs']) { $fields .= "|latest_logs"; } if ($vars['mark_found']) { $fields .= "|is_found"; } $vars['caches'] = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest($request->consumer, $request->token, array('cache_codes' => $cache_codes, 'langpref' => $langpref, 'fields' => $fields, 'lpc' => $lpc, 'user_uuid' => $user_uuid, 'log_fields' => 'uuid|date|user|type|comment|internal_id|was_recommended'))); # Get rid of invalid cache references. $valid = array(); foreach ($vars['caches'] as $key => &$ref) { if ($ref !== null) { $valid[$key] =& $ref; } } $vars['caches'] =& $valid; unset($valid); # Get all the other data need. $vars['installation'] = OkapiServiceRunner::call('services/apisrv/installation', new OkapiInternalRequest(new OkapiInternalConsumer(), null, array())); $vars['cache_GPX_types'] = self::$cache_GPX_types; $vars['cache_GPX_sizes'] = self::$cache_GPX_sizes; if (count($vars['attrs']) > 0) { /* The user asked for some kind of attribute output. We'll fetch all * the data we MAY need. This is often far too much, but thanks to * caching, it will work fast. */ $vars['attr_index'] = OkapiServiceRunner::call('services/attrs/attribute_index', new OkapiInternalRequest($request->consumer, $request->token, array('only_locally_used' => 'true', 'langpref' => $langpref, 'fields' => 'name|gc_equivs'))); # prepare GS attribute data $vars['gc_attrs'] = in_array('gc:attrs', $vars['attrs']); $vars['gc_ocde_attrs'] = in_array('gc_ocde:attrs', $vars['attrs']); if ($vars['gc_attrs'] || $vars['gc_ocde_attrs']) { if ($vars['gc_ocde_attrs']) { # As this is an OCDE compatibility feature, we use the same Pseudo-GS # attribute names here as OCDE. Note that this code is specific to OCDE # database; OCPL stores attribute names in a different way and may use # different names for equivalent attributes. $ocde_attrnames = Db::select_group_by('id', "\n select id, name\n from cache_attrib\n "); $attr_dict = AttrHelper::get_attrdict(); } foreach ($vars['caches'] as &$cache_ref) { $cache_ref['gc_attrs'] = array(); foreach ($cache_ref['attr_acodes'] as $acode) { $has_gc_equivs = false; foreach ($vars['attr_index'][$acode]['gc_equivs'] as $gc) { # The assignment via GC-ID as array key will prohibit duplicate # GC attributes, which can result from # - assigning the same GC ID to multiple A-Codes, # - contradicting attributes in one OC listing, e.g. 24/4 + not 24/7. $cache_ref['gc_attrs'][$gc['id']] = $gc; $has_gc_equivs = true; } if (!$has_gc_equivs && $vars['gc_ocde_attrs']) { # Generate an OCDE pseudo-GS attribute; # see https://github.com/opencaching/okapi/issues/190 and # https://github.com/opencaching/okapi/issues/271. # # Groundspeak uses ID 1..65 (as of June, 2013), and OCDE makeshift # IDs start at 106, so there is space for 40 new GS attributes. $internal_id = $attr_dict[$acode]['internal_id']; $cache_ref['gc_attrs'][100 + $internal_id] = array('inc' => 1, 'name' => $ocde_attrnames[$internal_id][0]['name']); } } } } } /* OC sites always used internal user_ids in their generated GPX files. * This might be considered an error in itself (Groundspeak's XML namespace * doesn't allow that), but it very common (Garmin's OpenCaching.COM * also does that). Therefore, for backward-compatibility reasons, OKAPI * will do it the same way. See issue 174. * * Currently, the caches method does not expose "owner.internal_id" and * "latest_logs.user.internal_id" fields, we will read them manually * from the database here. */ $dict = array(); foreach ($vars['caches'] as &$cache_ref) { $dict[$cache_ref['owner']['uuid']] = true; if (isset($cache_ref['latest_logs'])) { foreach ($cache_ref['latest_logs'] as &$log_ref) { $dict[$log_ref['user']['uuid']] = true; } } } $rs = Db::query("\n select uuid, user_id\n from user\n where uuid in ('" . implode("','", array_map('mysql_real_escape_string', array_keys($dict))) . "')\n "); while ($row = mysql_fetch_assoc($rs)) { $dict[$row['uuid']] = $row['user_id']; } $vars['user_uuid_to_internal_id'] =& $dict; unset($dict); # location_source (part 2 of 2) if ($location_source != 'default-coords') { $location_change_prefix = $request->get_parameter('location_change_prefix'); if (!$location_change_prefix) { $location_change_prefix = '# '; } # lets find requested coords foreach ($vars['caches'] as &$cache_ref) { foreach ($cache_ref['alt_wpts'] as $alt_wpt_key => $alt_wpt) { if ('alt_wpt:' . $alt_wpt['type'] == $location_source) { # Switch locations between primary wpt and alternate wpt. # Also alter the cache name and make sure to append a proper # notice. $original_location = $cache_ref['location']; $cache_ref['location'] = $alt_wpt['location']; $cache_ref['name_2'] = $location_change_prefix . $cache_ref['name']; if ($location_source == "alt_wpt:user-coords") { # In case of "user-coords", replace the default warning with a custom-tailored one. $cache_ref['warning_prefix'] = _("<b>Geocache coordinates have been changed.</b> They have been replaced with " . "your own custom coordinates which you have provided for this geocache."); } else { # Default warning $cache_ref['warning_prefix'] = _("<b>Geocache coordinates have been changed.</b> Currently they " . "point to one of the alternate waypoints originally described as:") . " " . $alt_wpt['description']; } # remove current alt waypoint unset($cache_ref['alt_wpts'][$alt_wpt_key]); # add original location as alternate if ($vars['alt_wpts']) { $cache_ref['alt_wpts'][] = array('name' => $cache_ref['code'] . '-DEFAULT-COORDS', 'location' => $original_location, 'type' => 'default-coords', 'type_name' => _("Original geocache location"), 'sym' => 'Block, Blue', 'description' => sprintf(_("Original (owner-supplied) location of the %s geocache"), $cache_ref['code'])); } break; } } } } # Do we need a GGZ index? if ($flags & self::FLAG_CREATE_GGZ_IDX) { # GGZ index consist of entries - one per each waypoint in the GPX file. # We will keep a list of all such entries here. $ggz_entries = array(); foreach ($vars['caches'] as &$cache_ref) { # Every $cache_ref will also be holding a reference to its entry. # Note, that more attributes are added while processing gpsfile.tpl.php! if (!isset($cache_ref['ggz_entry'])) { $cache_ref['ggz_entry'] = array(); } $ggz_entry =& $cache_ref['ggz_entry']; $ggz_entries[] =& $ggz_entry; $ggz_entry['code'] = $cache_ref['code']; $ggz_entry['name'] = isset($cache_ref['name_2']) ? $cache_ref['name_2'] : $cache_ref['name']; $ggz_entry['type'] = $vars['cache_GPX_types'][$cache_ref['type']]; list($lat, $lon) = explode("|", $cache_ref['location']); $ggz_entry['lat'] = $lat; $ggz_entry['lon'] = $lon; $ggz_entry['ratings'] = array(); $ratings_ref =& $ggz_entry['ratings']; if (isset($cache_ref['rating'])) { $ratings_ref['awesomeness'] = $cache_ref['rating']; } $ratings_ref['difficulty'] = $cache_ref['difficulty']; if (!isset($cache_ref['size'])) { $ratings_ref['size'] = 0; // Virtual, Event } else { if ($cache_ref['oxsize'] !== null) { // is this ox size one-to-one? $ratings_ref['size'] = $cache_ref['oxsize']; } } $ratings_ref['terrain'] = $cache_ref['terrain']; if ($vars['mark_found'] && $cache_ref['is_found']) { $ggz_entry['found'] = true; } # Additional waypoints. Currently, we're not 100% sure if their entries should # be included in the GGZ file (the format is undocumented). if (isset($cache_ref['alt_wpts'])) { $idx = 1; foreach ($cache_ref['alt_wpts'] as &$alt_wpt_ref) { if (!isset($alt_wpt_ref['ggz_entry'])) { $alt_wpt_ref['ggz_entry'] = array(); } $ggz_entry =& $alt_wpt_ref['ggz_entry']; $ggz_entries[] =& $ggz_entry; $ggz_entry['code'] = $cache_ref['code'] . '-' . $idx; $ggz_entry['name'] = $alt_wpt_ref['type_name']; $ggz_entry['type'] = $alt_wpt_ref['sym']; list($lat, $lon) = explode("|", $alt_wpt_ref['location']); $ggz_entry['lat'] = $lat; $ggz_entry['lon'] = $lon; $idx++; } } } } ob_start(); Okapi::gettext_domain_init(explode("|", $langpref)); # Consumer gets properly localized GPX file. include 'gpxfile.tpl.php'; Okapi::gettext_domain_restore(); $result = array('gpx' => ob_get_clean()); if ($flags & self::FLAG_CREATE_GGZ_IDX) { $result['ggz_entries'] = $ggz_entries; } return $result; }
public static function call(OkapiRequest $request) { # Read the parameters. $acodes = $request->get_parameter('acodes'); if (!$acodes) { throw new ParamMissing('acodes'); } $acodes = explode("|", $acodes); $langpref = $request->get_parameter('langpref'); if (!$langpref) { $langpref = "en"; } $langpref = explode("|", $langpref); $fields = $request->get_parameter('fields'); if (!$fields) { $fields = "name"; } $fields = explode("|", $fields); foreach ($fields as $field) { if (!in_array($field, self::$valid_field_names)) { throw new InvalidParam('fields', "'{$field}' is not a valid field code."); } } $forward_compatible = $request->get_parameter('forward_compatible'); if (!$forward_compatible) { $forward_compatible = "true"; } if (!in_array($forward_compatible, array("true", "false"))) { throw new InvalidParam('forward_compatible'); } $forward_compatible = $forward_compatible == "true"; # Load the attributes (all of them). require_once 'attr_helper.inc.php'; $attrdict = AttrHelper::get_attrdict(); # For each A-code, check if it exists, filter its fields and add it # to the results. $results = array(); foreach ($acodes as $acode) { /* Please note, that the $attr variable from the $attrdict dictionary * below is NOT fully compatible with the interface of the "attribute" * method. Some of $attr's fields are private and should not be exposed, * other fields don't exist and have to be added dynamically! */ if (isset($attrdict[$acode])) { $attr = $attrdict[$acode]; } elseif ($forward_compatible) { $attr = AttrHelper::get_unknown_placeholder($acode); } else { $results[$acode] = null; continue; } # Fill langpref-specific fields. $attr['name'] = Okapi::pick_best_language($attr['names'], $langpref); $attr['description'] = Okapi::pick_best_language($attr['descriptions'], $langpref); # Fill some other fields (not kept in the cached attrdict). $attr['is_locally_used'] = $attr['internal_id'] !== null; $attr['is_deprecated'] = $attr['is_discontinued']; // deprecated and undocumetned field, see issue 70 # Add to results. $results[$acode] = $attr; } # If the user wanted local_icon_urls, fetch them now. (We cannot cache them # in the $attrdict because currently we have no way of knowing then they # change.) if (in_array('local_icon_url', $fields)) { $tmp = Db::select_all("\n select id, icon_large\n from cache_attrib\n "); $map = array(); foreach ($tmp as &$row_ref) { $map[$row_ref['id']] =& $row_ref; } $prefix = Settings::get('SITE_URL'); foreach ($results as &$attr_ref) { $internal_id = $attr_ref['internal_id']; if (isset($map[$internal_id])) { $row = $map[$internal_id]; $attr_ref['local_icon_url'] = $prefix . $row['icon_large']; } else { $attr_ref['local_icon_url'] = null; } } } # Filter the fields. foreach ($results as &$attr_ref) { $clean_row = array(); foreach ($fields as $field) { $clean_row[$field] = $attr_ref[$field]; } $attr_ref = $clean_row; } return Okapi::formatted_response($request, $results); }