Merge pull request #148 from wrygiel/okapi
OKAPI Project update (r1031)
This commit is contained in:
commit
c6e3022fee
@ -23,75 +23,75 @@ require_once($GLOBALS['rootpath'].'okapi/urls.php');
|
||||
|
||||
if (ob_list_handlers() == array('default output handler'))
|
||||
{
|
||||
# We will assume that this one comes from "output_buffering" being turned on
|
||||
# in PHP config. This is very common and probably is good for most other OC
|
||||
# pages. But we don't need it in OKAPI. We will just turn this off.
|
||||
# We will assume that this one comes from "output_buffering" being turned on
|
||||
# in PHP config. This is very common and probably is good for most other OC
|
||||
# pages. But we don't need it in OKAPI. We will just turn this off.
|
||||
|
||||
ob_end_clean();
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
|
||||
class OkapiScriptEntryPointController
|
||||
{
|
||||
public static function dispatch_request($uri)
|
||||
{
|
||||
# Chop off the ?args=... part.
|
||||
public static function dispatch_request($uri)
|
||||
{
|
||||
# Chop off the ?args=... part.
|
||||
|
||||
if (strpos($uri, '?') !== false)
|
||||
$uri = substr($uri, 0, strpos($uri, '?'));
|
||||
if (strpos($uri, '?') !== false)
|
||||
$uri = substr($uri, 0, strpos($uri, '?'));
|
||||
|
||||
# Chop off everything before "/okapi/". This should work for okay for most "weird"
|
||||
# server configurations. It will also address a more subtle issue described here:
|
||||
# http://stackoverflow.com/questions/8040461/request-uri-unexpectedly-contains-fqdn
|
||||
# Chop off everything before "/okapi/". This should work for okay for most "weird"
|
||||
# server configurations. It will also address a more subtle issue described here:
|
||||
# http://stackoverflow.com/questions/8040461/request-uri-unexpectedly-contains-fqdn
|
||||
|
||||
if (strpos($uri, "/okapi/") !== false)
|
||||
$uri = substr($uri, strpos($uri, "/okapi/"));
|
||||
if (strpos($uri, "/okapi/") !== false)
|
||||
$uri = substr($uri, strpos($uri, "/okapi/"));
|
||||
|
||||
# Make sure we're in the right directory (.htaccess should make sure of that).
|
||||
# Make sure we're in the right directory (.htaccess should make sure of that).
|
||||
|
||||
if (strpos($uri, "/okapi/") !== 0)
|
||||
throw new Exception("'$uri' is outside of the /okapi/ path.");
|
||||
$uri = substr($uri, 7);
|
||||
if (strpos($uri, "/okapi/") !== 0)
|
||||
throw new Exception("'$uri' is outside of the /okapi/ path.");
|
||||
$uri = substr($uri, 7);
|
||||
|
||||
# Initializing internals and running pre-request cronjobs (we don't want
|
||||
# cronjobs to be run before "okapi/update", for example before database
|
||||
# was installed).
|
||||
# Initializing internals and running pre-request cronjobs (we don't want
|
||||
# cronjobs to be run before "okapi/update", for example before database
|
||||
# was installed).
|
||||
|
||||
$allow_cronjobs = ($uri != "update");
|
||||
Okapi::init_internals($allow_cronjobs);
|
||||
$allow_cronjobs = ($uri != "update");
|
||||
Okapi::init_internals($allow_cronjobs);
|
||||
|
||||
# Checking for allowed patterns...
|
||||
# Checking for allowed patterns...
|
||||
|
||||
try
|
||||
{
|
||||
foreach (OkapiUrls::$mapping as $pattern => $namespace)
|
||||
{
|
||||
$matches = null;
|
||||
if (preg_match("#$pattern#", $uri, $matches))
|
||||
{
|
||||
# Pattern matched! Moving on to the proper View...
|
||||
try
|
||||
{
|
||||
foreach (OkapiUrls::$mapping as $pattern => $namespace)
|
||||
{
|
||||
$matches = null;
|
||||
if (preg_match("#$pattern#", $uri, $matches))
|
||||
{
|
||||
# Pattern matched! Moving on to the proper View...
|
||||
|
||||
array_shift($matches);
|
||||
require_once($GLOBALS['rootpath']."okapi/views/$namespace.php");
|
||||
$response = call_user_func_array(array('\\okapi\\views\\'.
|
||||
str_replace('/', '\\', $namespace).'\\View', 'call'), $matches);
|
||||
if ($response)
|
||||
$response->display();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Http404 $e)
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
array_shift($matches);
|
||||
require_once($GLOBALS['rootpath']."okapi/views/$namespace.php");
|
||||
$response = call_user_func_array(array('\\okapi\\views\\'.
|
||||
str_replace('/', '\\', $namespace).'\\View', 'call'), $matches);
|
||||
if ($response)
|
||||
$response->display();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Http404 $e)
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
# None of the patterns matched OR method threw the Http404 exception.
|
||||
# None of the patterns matched OR method threw the Http404 exception.
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/views/http404.php");
|
||||
$response = \okapi\views\http404\View::call();
|
||||
$response->display();
|
||||
}
|
||||
require_once($GLOBALS['rootpath']."okapi/views/http404.php");
|
||||
$response = \okapi\views\http404\View::call();
|
||||
$response->display();
|
||||
}
|
||||
}
|
||||
|
||||
Okapi::gettext_domain_init();
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -6,180 +6,180 @@ use OAuthDataStore;
|
||||
|
||||
class OkapiDataStore extends OAuthDataStore
|
||||
{
|
||||
public function lookup_consumer($consumer_key)
|
||||
{
|
||||
$row = Db::select_row("
|
||||
select `key`, secret, name, url, email, admin
|
||||
from okapi_consumers
|
||||
where `key` = '".mysql_real_escape_string($consumer_key)."'
|
||||
");
|
||||
if (!$row)
|
||||
return null;
|
||||
return new OkapiConsumer($row['key'], $row['secret'], $row['name'],
|
||||
$row['url'], $row['email'], $row['admin'] ? true : false);
|
||||
}
|
||||
public function lookup_consumer($consumer_key)
|
||||
{
|
||||
$row = Db::select_row("
|
||||
select `key`, secret, name, url, email, admin
|
||||
from okapi_consumers
|
||||
where `key` = '".mysql_real_escape_string($consumer_key)."'
|
||||
");
|
||||
if (!$row)
|
||||
return null;
|
||||
return new OkapiConsumer($row['key'], $row['secret'], $row['name'],
|
||||
$row['url'], $row['email'], $row['admin'] ? true : false);
|
||||
}
|
||||
|
||||
public function lookup_token($consumer, $token_type, $token)
|
||||
{
|
||||
$row = Db::select_row("
|
||||
select `key`, consumer_key, secret, token_type, user_id, verifier, callback
|
||||
from okapi_tokens
|
||||
where
|
||||
consumer_key = '".mysql_real_escape_string($consumer->key)."'
|
||||
and token_type = '".mysql_real_escape_string($token_type)."'
|
||||
and `key` = '".mysql_real_escape_string($token)."'
|
||||
");
|
||||
if (!$row)
|
||||
return null;
|
||||
switch ($row['token_type'])
|
||||
{
|
||||
case 'request':
|
||||
return new OkapiRequestToken($row['key'], $row['secret'],
|
||||
$row['consumer_key'], $row['callback'], $row['user_id'],
|
||||
$row['verifier']);
|
||||
case 'access':
|
||||
return new OkapiAccessToken($row['key'], $row['secret'],
|
||||
$row['consumer_key'], $row['user_id']);
|
||||
default:
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
public function lookup_token($consumer, $token_type, $token)
|
||||
{
|
||||
$row = Db::select_row("
|
||||
select `key`, consumer_key, secret, token_type, user_id, verifier, callback
|
||||
from okapi_tokens
|
||||
where
|
||||
consumer_key = '".mysql_real_escape_string($consumer->key)."'
|
||||
and token_type = '".mysql_real_escape_string($token_type)."'
|
||||
and `key` = '".mysql_real_escape_string($token)."'
|
||||
");
|
||||
if (!$row)
|
||||
return null;
|
||||
switch ($row['token_type'])
|
||||
{
|
||||
case 'request':
|
||||
return new OkapiRequestToken($row['key'], $row['secret'],
|
||||
$row['consumer_key'], $row['callback'], $row['user_id'],
|
||||
$row['verifier']);
|
||||
case 'access':
|
||||
return new OkapiAccessToken($row['key'], $row['secret'],
|
||||
$row['consumer_key'], $row['user_id']);
|
||||
default:
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
public function lookup_nonce($consumer, $token, $nonce, $timestamp)
|
||||
{
|
||||
# Since it's not important for us to save the actual token and nonce
|
||||
# value, we will save a hash only. We could also include the consumer
|
||||
# key in this hash and drop the column, but we will leave it be for
|
||||
# now (for a couple of less important reasons).
|
||||
public function lookup_nonce($consumer, $token, $nonce, $timestamp)
|
||||
{
|
||||
# Since it's not important for us to save the actual token and nonce
|
||||
# value, we will save a hash only. We could also include the consumer
|
||||
# key in this hash and drop the column, but we will leave it be for
|
||||
# now (for a couple of less important reasons).
|
||||
|
||||
$nonce_hash = md5(serialize(array(
|
||||
$token ? $token->key : null,
|
||||
$timestamp,
|
||||
$nonce
|
||||
)));
|
||||
try
|
||||
{
|
||||
# Time timestamp is saved separately, because we are periodically
|
||||
# removing older nonces from the database (see cronjobs).
|
||||
$nonce_hash = md5(serialize(array(
|
||||
$token ? $token->key : null,
|
||||
$timestamp,
|
||||
$nonce
|
||||
)));
|
||||
try
|
||||
{
|
||||
# Time timestamp is saved separately, because we are periodically
|
||||
# removing older nonces from the database (see cronjobs).
|
||||
|
||||
Db::execute("
|
||||
insert into okapi_nonces (consumer_key, nonce_hash, timestamp)
|
||||
values (
|
||||
'".mysql_real_escape_string($consumer->key)."',
|
||||
'".mysql_real_escape_string($nonce_hash)."',
|
||||
'".mysql_real_escape_string($timestamp)."'
|
||||
);
|
||||
");
|
||||
return null;
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
# INSERT failed. This nonce was already used.
|
||||
Db::execute("
|
||||
insert into okapi_nonces (consumer_key, nonce_hash, timestamp)
|
||||
values (
|
||||
'".mysql_real_escape_string($consumer->key)."',
|
||||
'".mysql_real_escape_string($nonce_hash)."',
|
||||
'".mysql_real_escape_string($timestamp)."'
|
||||
);
|
||||
");
|
||||
return null;
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
# INSERT failed. This nonce was already used.
|
||||
|
||||
return $nonce;
|
||||
}
|
||||
}
|
||||
return $nonce;
|
||||
}
|
||||
}
|
||||
|
||||
public function new_request_token($consumer, $callback = null)
|
||||
{
|
||||
if ((preg_match("#^[a-z][a-z0-9_.-]*://#", $callback) > 0) ||
|
||||
$callback == "oob")
|
||||
{ /* ok */ }
|
||||
else { throw new BadRequest("oauth_callback should begin with <scheme>://, or should equal 'oob'."); }
|
||||
$token = new OkapiRequestToken(Okapi::generate_key(20), Okapi::generate_key(40),
|
||||
$consumer->key, $callback, null, Okapi::generate_key(8, true));
|
||||
Db::execute("
|
||||
insert into okapi_tokens
|
||||
(`key`, secret, token_type, timestamp,
|
||||
user_id, consumer_key, verifier, callback)
|
||||
values (
|
||||
'".mysql_real_escape_string($token->key)."',
|
||||
'".mysql_real_escape_string($token->secret)."',
|
||||
'request',
|
||||
unix_timestamp(),
|
||||
null,
|
||||
'".mysql_real_escape_string($consumer->key)."',
|
||||
'".mysql_real_escape_string($token->verifier)."',
|
||||
".(($token->callback_url == 'oob')
|
||||
? "null"
|
||||
: "'".mysql_real_escape_string($token->callback_url)."'"
|
||||
)."
|
||||
);
|
||||
");
|
||||
return $token;
|
||||
}
|
||||
public function new_request_token($consumer, $callback = null)
|
||||
{
|
||||
if ((preg_match("#^[a-z][a-z0-9_.-]*://#", $callback) > 0) ||
|
||||
$callback == "oob")
|
||||
{ /* ok */ }
|
||||
else { throw new BadRequest("oauth_callback should begin with lower case <scheme>://, or should equal 'oob'."); }
|
||||
$token = new OkapiRequestToken(Okapi::generate_key(20), Okapi::generate_key(40),
|
||||
$consumer->key, $callback, null, Okapi::generate_key(8, true));
|
||||
Db::execute("
|
||||
insert into okapi_tokens
|
||||
(`key`, secret, token_type, timestamp,
|
||||
user_id, consumer_key, verifier, callback)
|
||||
values (
|
||||
'".mysql_real_escape_string($token->key)."',
|
||||
'".mysql_real_escape_string($token->secret)."',
|
||||
'request',
|
||||
unix_timestamp(),
|
||||
null,
|
||||
'".mysql_real_escape_string($consumer->key)."',
|
||||
'".mysql_real_escape_string($token->verifier)."',
|
||||
".(($token->callback_url == 'oob')
|
||||
? "null"
|
||||
: "'".mysql_real_escape_string($token->callback_url)."'"
|
||||
)."
|
||||
);
|
||||
");
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function new_access_token($token, $consumer, $verifier = null)
|
||||
{
|
||||
if ($token->consumer_key != $consumer->key)
|
||||
throw new BadRequest("Request Token given is not associated with the Consumer who signed the request.");
|
||||
if (!$token->authorized_by_user_id)
|
||||
throw new BadRequest("Request Token given has not been authorized.");
|
||||
if ($token->verifier != $verifier)
|
||||
throw new BadRequest("Invalid verifier.");
|
||||
public function new_access_token($token, $consumer, $verifier = null)
|
||||
{
|
||||
if ($token->consumer_key != $consumer->key)
|
||||
throw new BadRequest("Request Token given is not associated with the Consumer who signed the request.");
|
||||
if (!$token->authorized_by_user_id)
|
||||
throw new BadRequest("Request Token given has not been authorized.");
|
||||
if ($token->verifier != $verifier)
|
||||
throw new BadRequest("Invalid verifier.");
|
||||
|
||||
# Invalidate the Request Token.
|
||||
# Invalidate the Request Token.
|
||||
|
||||
Db::execute("
|
||||
delete from okapi_tokens
|
||||
where `key` = '".mysql_real_escape_string($token->key)."'
|
||||
");
|
||||
Db::execute("
|
||||
delete from okapi_tokens
|
||||
where `key` = '".mysql_real_escape_string($token->key)."'
|
||||
");
|
||||
|
||||
# In OKAPI, all Access Tokens are long lived. Therefore, we don't want
|
||||
# to generate a new one every time a Consumer wants it. We will check
|
||||
# if there is already an Access Token generated for this (Consumer, User)
|
||||
# pair and return it if there is.
|
||||
# In OKAPI, all Access Tokens are long lived. Therefore, we don't want
|
||||
# to generate a new one every time a Consumer wants it. We will check
|
||||
# if there is already an Access Token generated for this (Consumer, User)
|
||||
# pair and return it if there is.
|
||||
|
||||
$row = Db::select_row("
|
||||
select `key`, secret
|
||||
from okapi_tokens
|
||||
where
|
||||
token_type = 'access'
|
||||
and user_id = '".mysql_real_escape_string($token->authorized_by_user_id)."'
|
||||
and consumer_key = '".mysql_real_escape_string($consumer->key)."'
|
||||
");
|
||||
if ($row)
|
||||
{
|
||||
# Use existing Access Token
|
||||
$row = Db::select_row("
|
||||
select `key`, secret
|
||||
from okapi_tokens
|
||||
where
|
||||
token_type = 'access'
|
||||
and user_id = '".mysql_real_escape_string($token->authorized_by_user_id)."'
|
||||
and consumer_key = '".mysql_real_escape_string($consumer->key)."'
|
||||
");
|
||||
if ($row)
|
||||
{
|
||||
# Use existing Access Token
|
||||
|
||||
$access_token = new OkapiAccessToken($row['key'], $row['secret'],
|
||||
$consumer->key, $token->authorized_by_user_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
# Generate a new Access Token.
|
||||
$access_token = new OkapiAccessToken($row['key'], $row['secret'],
|
||||
$consumer->key, $token->authorized_by_user_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
# Generate a new Access Token.
|
||||
|
||||
$access_token = new OkapiAccessToken(Okapi::generate_key(20), Okapi::generate_key(40),
|
||||
$consumer->key, $token->authorized_by_user_id);
|
||||
Db::execute("
|
||||
insert into okapi_tokens
|
||||
(`key`, secret, token_type, timestamp, user_id, consumer_key)
|
||||
values (
|
||||
'".mysql_real_escape_string($access_token->key)."',
|
||||
'".mysql_real_escape_string($access_token->secret)."',
|
||||
'access',
|
||||
unix_timestamp(),
|
||||
'".mysql_real_escape_string($access_token->user_id)."',
|
||||
'".mysql_real_escape_string($consumer->key)."'
|
||||
);
|
||||
");
|
||||
}
|
||||
return $access_token;
|
||||
}
|
||||
$access_token = new OkapiAccessToken(Okapi::generate_key(20), Okapi::generate_key(40),
|
||||
$consumer->key, $token->authorized_by_user_id);
|
||||
Db::execute("
|
||||
insert into okapi_tokens
|
||||
(`key`, secret, token_type, timestamp, user_id, consumer_key)
|
||||
values (
|
||||
'".mysql_real_escape_string($access_token->key)."',
|
||||
'".mysql_real_escape_string($access_token->secret)."',
|
||||
'access',
|
||||
unix_timestamp(),
|
||||
'".mysql_real_escape_string($access_token->user_id)."',
|
||||
'".mysql_real_escape_string($consumer->key)."'
|
||||
);
|
||||
");
|
||||
}
|
||||
return $access_token;
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
Db::execute("
|
||||
delete from okapi_nonces
|
||||
where
|
||||
timestamp < unix_timestamp(date_add(now(), interval -6 minute))
|
||||
or timestamp > unix_timestamp(date_add(now(), interval 6 minute))
|
||||
");
|
||||
Db::execute("
|
||||
delete from okapi_tokens
|
||||
where
|
||||
token_type = 'request'
|
||||
and timestamp < unix_timestamp(date_add(now(), interval -2 hour))
|
||||
");
|
||||
}
|
||||
public function cleanup()
|
||||
{
|
||||
Db::execute("
|
||||
delete from okapi_nonces
|
||||
where
|
||||
timestamp < unix_timestamp(date_add(now(), interval -6 minute))
|
||||
or timestamp > unix_timestamp(date_add(now(), interval 6 minute))
|
||||
");
|
||||
Db::execute("
|
||||
delete from okapi_tokens
|
||||
where
|
||||
token_type = 'request'
|
||||
and timestamp < unix_timestamp(date_add(now(), interval -2 hour))
|
||||
");
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use okapi\OkapiFacadeConsumer;
|
||||
use okapi\OkapiFacadeAccessToken;
|
||||
use okapi\Cache;
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/core.php");
|
||||
OkapiErrorHandler::$treat_notices_as_errors = true;
|
||||
@ -45,131 +46,214 @@ Okapi::init_internals();
|
||||
*/
|
||||
class Facade
|
||||
{
|
||||
/**
|
||||
* Perform OKAPI service call, signed by internal 'facade' consumer key, and return the result
|
||||
* (this will be PHP object or OkapiHttpResponse, depending on the method). Use this method
|
||||
* whenever you need to access OKAPI services from within OC code. If you want to simulate
|
||||
* Level 3 Authentication, you should supply user's internal ID (the second parameter).
|
||||
*/
|
||||
public static function service_call($service_name, $user_id_or_null, $parameters)
|
||||
{
|
||||
$request = new OkapiInternalRequest(
|
||||
new OkapiFacadeConsumer(),
|
||||
($user_id_or_null !== null) ? new OkapiFacadeAccessToken($user_id_or_null) : null,
|
||||
$parameters
|
||||
);
|
||||
$request->perceive_as_http_request = true;
|
||||
return OkapiServiceRunner::call($service_name, $request);
|
||||
}
|
||||
/**
|
||||
* Perform OKAPI service call, signed by internal 'facade' consumer key, and return the result
|
||||
* (this will be PHP object or OkapiHttpResponse, depending on the method). Use this method
|
||||
* whenever you need to access OKAPI services from within OC code. If you want to simulate
|
||||
* Level 3 Authentication, you should supply user's internal ID (the second parameter).
|
||||
*/
|
||||
public static function service_call($service_name, $user_id_or_null, $parameters)
|
||||
{
|
||||
$request = new OkapiInternalRequest(
|
||||
new OkapiFacadeConsumer(),
|
||||
($user_id_or_null !== null) ? new OkapiFacadeAccessToken($user_id_or_null) : null,
|
||||
$parameters
|
||||
);
|
||||
$request->perceive_as_http_request = true;
|
||||
return OkapiServiceRunner::call($service_name, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* This works like service_call with two exceptions: 1. It passes all your
|
||||
* current HTTP request headers to OKAPI (which can make use of them in
|
||||
* terms of caching), 2. It outputs the service response directly, instead
|
||||
* of returning it.
|
||||
*/
|
||||
public static function service_display($service_name, $user_id_or_null, $parameters)
|
||||
{
|
||||
$request = new OkapiInternalRequest(
|
||||
new OkapiFacadeConsumer(),
|
||||
($user_id_or_null !== null) ? new OkapiFacadeAccessToken($user_id_or_null) : null,
|
||||
$parameters
|
||||
);
|
||||
$request->perceive_as_http_request = true;
|
||||
if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
|
||||
$request->etag = $_SERVER['HTTP_IF_NONE_MATCH'];
|
||||
$response = OkapiServiceRunner::call($service_name, $request);
|
||||
$response->display();
|
||||
}
|
||||
/**
|
||||
* This works like service_call with two exceptions: 1. It passes all your
|
||||
* current HTTP request headers to OKAPI (which can make use of them in
|
||||
* terms of caching), 2. It outputs the service response directly, instead
|
||||
* of returning it.
|
||||
*/
|
||||
public static function service_display($service_name, $user_id_or_null, $parameters)
|
||||
{
|
||||
$request = new OkapiInternalRequest(
|
||||
new OkapiFacadeConsumer(),
|
||||
($user_id_or_null !== null) ? new OkapiFacadeAccessToken($user_id_or_null) : null,
|
||||
$parameters
|
||||
);
|
||||
$request->perceive_as_http_request = true;
|
||||
if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
|
||||
$request->etag = $_SERVER['HTTP_IF_NONE_MATCH'];
|
||||
$response = OkapiServiceRunner::call($service_name, $request);
|
||||
$response->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a search set from a temporary table. This is very similar to
|
||||
* the "services/caches/search/save" method, but allows OC server to
|
||||
* include its own result instead of using OKAPI's search options. The
|
||||
* $temp_table should be a valid name of a temporary table with the
|
||||
* following (or similar) structure:
|
||||
*
|
||||
* create temporary table temp_12345 (
|
||||
* cache_id integer primary key
|
||||
* ) engine=memory;
|
||||
*/
|
||||
public static function import_search_set($temp_table, $min_store, $max_ref_age)
|
||||
{
|
||||
require_once 'services/caches/search/save.php';
|
||||
$tables = array('caches', $temp_table);
|
||||
$where_conds = array(
|
||||
$temp_table.".cache_id = caches.cache_id",
|
||||
'caches.status in (1,2,3)',
|
||||
);
|
||||
return \okapi\services\caches\search\save\WebService::get_set(
|
||||
$tables, $where_conds, $min_store, $max_ref_age
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Create a search set from a temporary table. This is very similar to
|
||||
* the "services/caches/search/save" method, but allows OC server to
|
||||
* include its own result instead of using OKAPI's search options. The
|
||||
* $temp_table should be a valid name of a temporary table with the
|
||||
* following (or similar) structure:
|
||||
*
|
||||
* create temporary table temp_12345 (
|
||||
* cache_id integer primary key
|
||||
* ) engine=memory;
|
||||
*/
|
||||
public static function import_search_set($temp_table, $min_store, $max_ref_age)
|
||||
{
|
||||
require_once($GLOBALS['rootpath'].'okapi/services/caches/search/save.php');
|
||||
$tables = array('caches', $temp_table);
|
||||
$where_conds = array(
|
||||
$temp_table.".cache_id = caches.cache_id",
|
||||
'caches.status in (1,2,3)',
|
||||
);
|
||||
return \okapi\services\caches\search\save\WebService::get_set(
|
||||
$tables, $where_conds, $min_store, $max_ref_age
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the specified caches as *possibly* modified. The replicate module
|
||||
* will scan for changes within these caches on the next changelog update.
|
||||
* This is useful in some cases, when OKAPI cannot detect the modification
|
||||
* for itself (grep OCPL code for examples). See issue #179.
|
||||
*
|
||||
* $cache_codes - a single cache code OR an array of cache codes.
|
||||
*/
|
||||
public static function schedule_geocache_check($cache_codes)
|
||||
{
|
||||
if (!is_array($cache_codes))
|
||||
$cache_codes = array($cache_codes);
|
||||
Db::execute("
|
||||
update caches
|
||||
set okapi_syncbase = now()
|
||||
where wp_oc in ('".implode("','", array_map('mysql_real_escape_string', $cache_codes))."')
|
||||
");
|
||||
}
|
||||
/**
|
||||
* Mark the specified caches as *possibly* modified. The replicate module
|
||||
* will scan for changes within these caches on the next changelog update.
|
||||
* This is useful in some cases, when OKAPI cannot detect the modification
|
||||
* for itself (grep OCPL code for examples). See issue #179.
|
||||
*
|
||||
* $cache_codes - a single cache code OR an array of cache codes.
|
||||
*/
|
||||
public static function schedule_geocache_check($cache_codes)
|
||||
{
|
||||
if (!is_array($cache_codes))
|
||||
$cache_codes = array($cache_codes);
|
||||
Db::execute("
|
||||
update caches
|
||||
set okapi_syncbase = now()
|
||||
where wp_oc in ('".implode("','", array_map('mysql_real_escape_string', $cache_codes))."')
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all log entries of the specified user for the specified cache and
|
||||
* mark them as *possibly* modified. See issue #265.
|
||||
*
|
||||
* $cache_id - internal ID of the geocache,
|
||||
* $user_id - internal ID of the user.
|
||||
*/
|
||||
public static function schedule_user_entries_check($cache_id, $user_id)
|
||||
{
|
||||
Db::execute("
|
||||
update cache_logs
|
||||
set okapi_syncbase = now()
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($cache_id)."'
|
||||
and user_id = '".mysql_real_escape_string($user_id)."'
|
||||
");
|
||||
}
|
||||
/**
|
||||
* Find all log entries of the specified user for the specified cache and
|
||||
* mark them as *possibly* modified. See issue #265.
|
||||
*
|
||||
* $cache_id - internal ID of the geocache,
|
||||
* $user_id - internal ID of the user.
|
||||
*/
|
||||
public static function schedule_user_entries_check($cache_id, $user_id)
|
||||
{
|
||||
Db::execute("
|
||||
update cache_logs
|
||||
set okapi_syncbase = now()
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($cache_id)."'
|
||||
and user_id = '".mysql_real_escape_string($user_id)."'
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Run OKAPI database update.
|
||||
* Will output messages to stdout.
|
||||
*/
|
||||
public static function database_update()
|
||||
{
|
||||
require_once($GLOBALS['rootpath']."okapi/views/update.php");
|
||||
$update = new views\update\View;
|
||||
$update->call();
|
||||
}
|
||||
/**
|
||||
* Run OKAPI database update.
|
||||
* Will output messages to stdout.
|
||||
*/
|
||||
public static function database_update()
|
||||
{
|
||||
require_once($GLOBALS['rootpath']."okapi/views/update.php");
|
||||
$update = new views\update\View;
|
||||
$update->call();
|
||||
}
|
||||
|
||||
/**
|
||||
* You will probably want to call that with FALSE when using Facade
|
||||
* in buggy, legacy OC code. This will disable OKAPI's default behavior
|
||||
* of treating NOTICEs as errors.
|
||||
*/
|
||||
public static function disable_error_handling()
|
||||
{
|
||||
OkapiErrorHandler::disable();
|
||||
}
|
||||
/**
|
||||
* You will probably want to call that with FALSE when using Facade
|
||||
* in buggy, legacy OC code. This will disable OKAPI's default behavior
|
||||
* of treating NOTICEs as errors.
|
||||
*/
|
||||
public static function disable_error_handling()
|
||||
{
|
||||
OkapiErrorHandler::disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* If you disabled OKAPI's error handling with disable_error_handling,
|
||||
* you may reenable it with this method.
|
||||
*/
|
||||
public static function reenable_error_handling()
|
||||
{
|
||||
OkapiErrorHandler::reenable();
|
||||
}
|
||||
/**
|
||||
* If you disabled OKAPI's error handling with disable_error_handling,
|
||||
* you may reenable it with this method.
|
||||
*/
|
||||
public static function reenable_error_handling()
|
||||
{
|
||||
OkapiErrorHandler::reenable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the object $value in OKAPI's cache, under the name of $key.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* $key -- must be a string of max 57 characters in length (you can use
|
||||
* md5(...) to shorten your keys). Use the same $key to retrieve your
|
||||
* value later.
|
||||
*
|
||||
* $value -- can be any serializable PHP object. Currently there's no
|
||||
* strict size limit, but try to keep it below 1 MB (for future
|
||||
* compatibility with memcached).
|
||||
*
|
||||
* $timeout -- *maximum* time allowed to store the value, given in seconds
|
||||
* (however, the value *can* be removed sooner than that, see the note
|
||||
* below). Timeout can be also set to null, but you should avoid this,
|
||||
* because such objects may clutter the cache unnecessarilly. (You must
|
||||
* remember to remove them yourself!)
|
||||
*
|
||||
* Please note, that this cache is not guaranteed to be persistent.
|
||||
* Usually it is, but it can be emptied in case of emergency (low disk
|
||||
* space), or if we decide to switch the underlying cache engine in the
|
||||
* future (e.g. to memcached). Most of your values should be safe though.
|
||||
*/
|
||||
public static function cache_set($key, $value, $timeout)
|
||||
{
|
||||
Cache::set("facade#".$key, $value, $timeout);
|
||||
}
|
||||
|
||||
/** Same as `cache_set`, but works on many key->value pair at once. */
|
||||
public static function cache_set_many($dict, $timeout)
|
||||
{
|
||||
$prefixed_dict = array();
|
||||
foreach ($dict as $key => &$value_ref) {
|
||||
$prefixed_dict["facade#".$key] = &$value_ref;
|
||||
}
|
||||
Cache::set_many($prefixed_dict, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve object stored in cache under the name of $key. If object does
|
||||
* not exist or its timeout has expired, return null.
|
||||
*/
|
||||
public static function cache_get($key)
|
||||
{
|
||||
return Cache::get("facade#".$key);
|
||||
}
|
||||
|
||||
/** Same as `cache_get`, but it works on multiple keys at once. */
|
||||
public static function get_many($keys)
|
||||
{
|
||||
$prefixed_keys = array();
|
||||
foreach ($keys as $key) {
|
||||
$prefixed_keys[] = "facade#".$key;
|
||||
}
|
||||
$prefixed_result = Cache::get_many($prefixed_keys);
|
||||
$result = array();
|
||||
foreach ($prefixed_result as $prefixed_key => &$value_ref) {
|
||||
$result[substr($prefixed_key, 7)] = &$value_ref;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the entry named $key from the cache.
|
||||
*/
|
||||
public static function cache_delete($key)
|
||||
{
|
||||
Cache::delete("facade#".$key);
|
||||
}
|
||||
|
||||
/** Same as `cache_delete`, but works on many keys at once. */
|
||||
public static function cache_delete_many($keys)
|
||||
{
|
||||
$prefixed_keys = array();
|
||||
foreach ($keys as $key) {
|
||||
$prefixed_keys[] = "facade#".$key;
|
||||
}
|
||||
Cache::delete_many($prefixed_keys);
|
||||
}
|
||||
}
|
||||
|
||||
# (This comment is added here simply to debug OKAPI deployment.....)
|
||||
|
@ -8,23 +8,23 @@ namespace okapi;
|
||||
*/
|
||||
class OCSession
|
||||
{
|
||||
/** Return ID of currently logged in user or NULL if no user is logged in. */
|
||||
public static function get_user_id()
|
||||
{
|
||||
static $cached_result = false;
|
||||
if ($cached_result !== false)
|
||||
return $cached_result;
|
||||
/** Return ID of currently logged in user or NULL if no user is logged in. */
|
||||
public static function get_user_id()
|
||||
{
|
||||
static $cached_result = false;
|
||||
if ($cached_result !== false)
|
||||
return $cached_result;
|
||||
|
||||
$cookie_name = Settings::get('OC_COOKIE_NAME');
|
||||
if (!isset($_COOKIE[$cookie_name]))
|
||||
return null;
|
||||
$OC_data = unserialize(base64_decode($_COOKIE[$cookie_name]));
|
||||
if (!isset($OC_data['sessionid']))
|
||||
return null;
|
||||
$OC_sessionid = $OC_data['sessionid'];
|
||||
if (!$OC_sessionid)
|
||||
return null;
|
||||
$cookie_name = Settings::get('OC_COOKIE_NAME');
|
||||
if (!isset($_COOKIE[$cookie_name]))
|
||||
return null;
|
||||
$OC_data = unserialize(base64_decode($_COOKIE[$cookie_name]));
|
||||
if (!isset($OC_data['sessionid']))
|
||||
return null;
|
||||
$OC_sessionid = $OC_data['sessionid'];
|
||||
if (!$OC_sessionid)
|
||||
return null;
|
||||
|
||||
return Db::select_value("select user_id from sys_sessions where uuid='".mysql_real_escape_string($OC_sessionid)."'");
|
||||
}
|
||||
return Db::select_value("select user_id from sys_sessions where uuid='".mysql_real_escape_string($OC_sessionid)."'");
|
||||
}
|
||||
}
|
Binary file not shown.
@ -2,11 +2,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OKAPI\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-07-10 12:30+0100\n"
|
||||
"PO-Revision-Date: 2013-07-10 12:31+0100\n"
|
||||
"Last-Translator: following <following@online.de>\n"
|
||||
"POT-Creation-Date: 2014-01-23 15:51+0100\n"
|
||||
"PO-Revision-Date: 2014-01-23 15:52+0100\n"
|
||||
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
||||
"Language-Team: following <following@online.de>\n"
|
||||
"Language: German\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@ -14,20 +14,29 @@ msgstr ""
|
||||
"X-Poedit-Basepath: .\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Generator: Poedit 1.5.5\n"
|
||||
"X-Generator: Poedit 1.6.3\n"
|
||||
"X-Poedit-SearchPath-0: c:\\source\\oc\\server-3.0\\htdocs\\okapi\n"
|
||||
"X-Poedit-SearchPath-1: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api"
|
||||
"\\okapi\n"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/geocaches.php:956
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:957
|
||||
msgid "Stage"
|
||||
msgstr "Station"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/geocaches.php:1108
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:986
|
||||
msgid "User location"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:989
|
||||
#, php-format
|
||||
msgid "Your own custom coordinates for the %s geocache"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:1148
|
||||
msgid "National Park / Landscape"
|
||||
msgstr "Nationalpark / Landschaft"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/geocaches.php:1260
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:1300
|
||||
#, php-format
|
||||
msgid ""
|
||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||
@ -35,7 +44,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Diese <a href='%s'>Cache</a>-Beschreibung stammt von <a href='%s'>%s</a>."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/geocaches.php:1272
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:1312
|
||||
#, php-format
|
||||
msgid ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
@ -46,7 +55,7 @@ msgstr ""
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/de/'>CC-BY-NC-ND</a>, Stand: %s; "
|
||||
"alle Logeinträge © jeweiliger Autor"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/geocaches.php:1283
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:1323
|
||||
#, php-format
|
||||
msgid ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
@ -57,63 +66,84 @@ msgstr ""
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/de/'>CC-BY-NC-ND</a>; alle "
|
||||
"Logeinträge © jeweiliger Autor"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:31
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:60
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:360
|
||||
msgid ""
|
||||
"<b>Geocache coordinates have been changed.</b> They have been replaced with "
|
||||
"your own custom coordinates which you have provided for this geocache."
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:366
|
||||
msgid ""
|
||||
"<b>Geocache coordinates have been changed.</b> Currently they point to one "
|
||||
"of the alternate waypoints originally described as:"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:379
|
||||
msgid "Original geocache location"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:381
|
||||
#, php-format
|
||||
msgid "Original (owner-supplied) location of the %s geocache"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:30
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
msgid "hidden by"
|
||||
msgstr "versteckt von"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:64
|
||||
#, php-format
|
||||
msgid "%d recommendation"
|
||||
msgid_plural "%d recommendations"
|
||||
msgstr[0] "%d Empfehlung"
|
||||
msgstr[1] "%d Empfehlungen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:63
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:65
|
||||
#, php-format
|
||||
msgid "found %d time"
|
||||
msgid_plural "found %d times"
|
||||
msgstr[0] "%d mal gefunden"
|
||||
msgstr[1] "%d mal gefunden"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:66
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:68
|
||||
#, php-format
|
||||
msgid "%d trackable"
|
||||
msgid_plural "%d trackables"
|
||||
msgstr[0] "%d Geokret"
|
||||
msgstr[1] "%d Geokrets"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:70
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:72
|
||||
msgid "Personal notes"
|
||||
msgstr "Persönliche Notizen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:74
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:76
|
||||
msgid "Attributes"
|
||||
msgstr "Attribute"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:78
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:80
|
||||
msgid "Trackables"
|
||||
msgstr "Geokrets"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:88
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:104
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:90
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:106
|
||||
msgid "Images"
|
||||
msgstr "Bilder"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:111
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:113
|
||||
msgid "Spoilers"
|
||||
msgstr "Spoiler"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:120
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:122
|
||||
msgid "Image descriptions"
|
||||
msgstr "Bildbeschreibungen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:128
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:130
|
||||
msgid "The cache probably is located in the following protection areas:"
|
||||
msgstr ""
|
||||
"Der Geocache befindet sich wahrscheinlich in den folgenden Schutzgebieten:"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:70
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:70
|
||||
msgid ""
|
||||
"You are trying to publish a log entry with a date in future. Cache log "
|
||||
"entries are allowed to be published in the past, but NOT in the future."
|
||||
@ -121,7 +151,7 @@ msgstr ""
|
||||
"Das Datum deines Logeintrags liegt in der Zukunft. Cache-Logs können nur für "
|
||||
"die Vergangenheit oder für heute eingetragen werden."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:92
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:92
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your cache rating was ignored, because %s does not have a rating "
|
||||
@ -129,7 +159,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Deine Cachewertung wurde jedoch ignoriert, weil %s kein Bewertungssystem hat."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:111
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:111
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your cache recommendation was ignored, because %s does not allow "
|
||||
@ -138,7 +168,7 @@ msgstr ""
|
||||
"Deine Empfehlung wurde jedoch ignoriert, weil auf %s keine Event-Caches "
|
||||
"empfohlen werden können."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:125
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:125
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
||||
@ -147,7 +177,7 @@ msgstr ""
|
||||
"Deine Angabe \"benötigt Wartung\" wurde jedoch ignoriert, weil es diese "
|
||||
"Funktion bei %s nicht gibt."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:145
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:145
|
||||
msgid ""
|
||||
"This cache is an Event cache. You cannot \"Find\" it (but you can attend it, "
|
||||
"or comment on it)!"
|
||||
@ -155,7 +185,7 @@ msgstr ""
|
||||
"Dies ist ein Event-Cache. Du kannst ihn nicht \"finden\" (aber du kannst am "
|
||||
"Event teilnehmen oder einen Hinweis loggen)."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:150
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:150
|
||||
msgid ""
|
||||
"This cache is NOT an Event cache. You cannot \"Attend\" it (but you can find "
|
||||
"it, or comment on it)!"
|
||||
@ -163,26 +193,26 @@ msgstr ""
|
||||
"Dies ist KEIN Event-Cache. Du kannst an ihm nicht \"teilnehmen\" (aber du "
|
||||
"kannst ihn finden oder kommentieren)."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:155
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:155
|
||||
msgid "Your have to supply some text for your comment."
|
||||
msgstr "Du musst einen Text für dein Hinweislog eingeben!"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:168
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:168
|
||||
msgid "This cache requires a password. You didn't provide one!"
|
||||
msgstr ""
|
||||
"Dieser Cache kann nur mit Kennwort geloggt werden, aber du hast keines "
|
||||
"angegeben."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:170
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:170
|
||||
msgid "Invalid password!"
|
||||
msgstr "Ungültiges Kennwort!"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:282
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:285
|
||||
msgid "You have already submitted a log entry with exactly the same contents."
|
||||
msgstr ""
|
||||
"Du hast bereits einen Logeintrag mit genau dem gleichen Inhalt gemacht."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:305
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:308
|
||||
msgid ""
|
||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||
"\"Comments\" only!"
|
||||
@ -190,53 +220,53 @@ msgstr ""
|
||||
"Du hast diesen Cache bereits als gefunden geloggt. Ein zweites Fundlog ist "
|
||||
"nicht möglich, aber du kannst stattdessen einen Hinweis loggen."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:307
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:310
|
||||
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||
msgstr ""
|
||||
"Als Besitzer des Caches kannst du nur Hinweise loggen, keine Funde oder "
|
||||
"Nichtfunde."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:325
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:328
|
||||
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||
msgstr ""
|
||||
"Du hast diesen Cache bereits bewertet. Deine Bewertung ist nicht änderbar."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:342
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:345
|
||||
msgid "You have already recommended this cache once."
|
||||
msgstr "Du hast diesen Cache bereits empfohlen."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:352
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:355
|
||||
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||
msgstr ""
|
||||
"Du musst mehr Caches finden, um eine weitere Bewertung abgeben zu können!"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:395
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:398
|
||||
msgid "Event caches cannot \"need maintenance\"."
|
||||
msgstr "Event-Caches können keine \"Wartung benötigen\"."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:525
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:528
|
||||
msgid "Your cache log entry was posted successfully."
|
||||
msgstr "Dein Log wurde veröffentlicht."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:5
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:5
|
||||
msgid "Authorization Form"
|
||||
msgstr "Authorisierungs-Formular"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:46
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:46
|
||||
msgid "Expired request"
|
||||
msgstr "Anfrage abgelaufen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:47
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:47
|
||||
msgid "Unfortunately, the request has expired. Please try again."
|
||||
msgstr ""
|
||||
"Die Anfrage ist wegen Zeitüberschreitung abgelaufen. Bitte versuche es noch "
|
||||
"einmal."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:49
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:49
|
||||
msgid "External application is requesting access..."
|
||||
msgstr "Eine externe Anwendung wünscht Zugriff ..."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:50
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:50
|
||||
#, php-format
|
||||
msgid ""
|
||||
"<b>%s</b> wants to access your <b>%s</b> account. Do you agree to grant "
|
||||
@ -245,28 +275,29 @@ msgstr ""
|
||||
"<b>%s</b> möchte auf dein <b>%s</b>-Benutzerkonto zugreifen. Möchtest du "
|
||||
"dieser Anwendung Zugriff gewähren?"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:53
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:53
|
||||
msgid "I agree"
|
||||
msgstr "Ja"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:54
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:54
|
||||
msgid "Decline"
|
||||
msgstr "Nein"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:56
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:56
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
||||
"OKAPI Framework</a>.\n"
|
||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
||||
"methods delivered\n"
|
||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
||||
"name.\n"
|
||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>Once permission is granted it is valid until its "
|
||||
"withdrawal on\n"
|
||||
" the <a href='%s'>applications management</a> page.</p>\n"
|
||||
" <p>The application will access your acount via <a "
|
||||
"href='%s'>the OKAPI Framework</a>.\n"
|
||||
" If you allow this request application will be able to "
|
||||
"access all methods delivered\n"
|
||||
" by the OKAPI Framework, i.e. post log entries on "
|
||||
"geocaches in your name.\n"
|
||||
" You can revoke this permission at any moment.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Wenn die Erlaubnis erteilt wurde, ist sie so lange gültig, bis "
|
||||
@ -281,23 +312,23 @@ msgstr ""
|
||||
"\t\t\t\t\tDu kannst diese Erlaubnis jederzeit widerrufen.</p>\n"
|
||||
"\t\t\t\t"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorized.tpl.php:5
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorized.tpl.php:5
|
||||
msgid "Authorization Succeeded"
|
||||
msgstr "Authorisierung erfolgreich"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorized.tpl.php:28
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorized.tpl.php:28
|
||||
msgid "Access successfully granted"
|
||||
msgstr "Zugang wurde gewährt"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorized.tpl.php:29
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorized.tpl.php:29
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
||||
"b>\n"
|
||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
||||
"code:</p>\n"
|
||||
"\t\t\t"
|
||||
" <p><b>You've just granted %s application access to your %s "
|
||||
"account.</b>\n"
|
||||
" To complete the operation, go back to %s and enter the "
|
||||
"following PIN code:</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>Du hast der Anwendung \"%s\" Zugriff auf dein %s-Benutzerkonto "
|
||||
@ -306,26 +337,26 @@ msgstr ""
|
||||
"PIN-Code ein:</p>\n"
|
||||
"\t\t\t"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:5
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:5
|
||||
msgid "My Apps"
|
||||
msgstr "Meine Apps"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:29
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:29
|
||||
msgid "Your external applications"
|
||||
msgstr "Deine externen Anwendungen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:31
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:31
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
||||
"your <b>%s</b> account.\n"
|
||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
||||
"privileges.\n"
|
||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
||||
"to perform any\n"
|
||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>This is the list of applications which you granted "
|
||||
"access to your <b>%s</b> account.\n"
|
||||
" This page gives you the abbility to revoke all "
|
||||
"previously granted privileges.\n"
|
||||
" Once you click \"remove\" the application will no longer "
|
||||
"be able to perform any\n"
|
||||
" actions on your behalf.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Dies ist eine Liste der Anwendungen, denen du Zugriff auf dein "
|
||||
@ -336,21 +367,21 @@ msgstr ""
|
||||
"Aktionen mehr unter deinem \t\t\t\t\tBenutzername ausführen können.</p>\n"
|
||||
"\t\t\t\t"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:45
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:45
|
||||
msgid "remove"
|
||||
msgstr "entfernen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:50
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:50
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
||||
"external applications\n"
|
||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
||||
"authorized to act\n"
|
||||
"\t\t\t\t\ton your behalf. Once you start using external Opencaching "
|
||||
"applications, they will appear here.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>Thanks to the <a href='%s'>OKAPI Framework</a> you "
|
||||
"can grant external applications\n"
|
||||
" access to your <b>%s</b> account. Currently no "
|
||||
"applications are authorized to act\n"
|
||||
" on your behalf. Once you start using external "
|
||||
"Opencaching applications, they will appear here.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Die <a href='%s'>OKAPI-Schnittstelle</a> ermöglichst es dir, "
|
||||
|
Binary file not shown.
@ -2,11 +2,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OKAPI\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-07-19 08:41+0100\n"
|
||||
"PO-Revision-Date: 2013-07-19 08:46+0100\n"
|
||||
"Last-Translator: faina09 <stefanocotterli@gmail.com>\n"
|
||||
"POT-Creation-Date: 2014-01-23 15:53+0100\n"
|
||||
"PO-Revision-Date: 2014-01-23 16:04+0100\n"
|
||||
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
||||
"Language-Team: following <following@online.de>\n"
|
||||
"Language: Italian\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@ -14,22 +14,31 @@ msgstr ""
|
||||
"X-Poedit-Basepath: .\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Generator: Poedit 1.5.7\n"
|
||||
"X-Generator: Poedit 1.6.3\n"
|
||||
"X-Poedit-SearchPath-0: c:\\source\\okapi\\following2\n"
|
||||
"X-Poedit-SearchPath-1: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api"
|
||||
"\\okapi\n"
|
||||
"X-Poedit-SearchPath-2: C:\\Users\\stefano.cotterli\\Desktop\\opencaching-"
|
||||
"api\n"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/geocaches.php:956
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:957
|
||||
msgid "Stage"
|
||||
msgstr "Passo"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/geocaches.php:1111
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:986
|
||||
msgid "User location"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:989
|
||||
#, php-format
|
||||
msgid "Your own custom coordinates for the %s geocache"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:1148
|
||||
msgid "National Park / Landscape"
|
||||
msgstr "Parco Nazionale / Paesaggio"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/geocaches.php:1263
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:1300
|
||||
#, php-format
|
||||
msgid ""
|
||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||
@ -38,7 +47,7 @@ msgstr ""
|
||||
"La deescrizione di questa <a href='%s'>geocache</a>proviene dal sito <a "
|
||||
"href='%s'>%s</a>."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/geocaches.php:1275
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:1312
|
||||
#, php-format
|
||||
msgid ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
@ -46,7 +55,7 @@ msgid ""
|
||||
"%s; all log entries © their authors"
|
||||
msgstr ""
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/geocaches.php:1286
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/geocaches.php:1323
|
||||
#, php-format
|
||||
msgid ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
@ -54,62 +63,83 @@ msgid ""
|
||||
"log entries © their authors"
|
||||
msgstr ""
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:31
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:60
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:360
|
||||
msgid ""
|
||||
"<b>Geocache coordinates have been changed.</b> They have been replaced with "
|
||||
"your own custom coordinates which you have provided for this geocache."
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:366
|
||||
msgid ""
|
||||
"<b>Geocache coordinates have been changed.</b> Currently they point to one "
|
||||
"of the alternate waypoints originally described as:"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:379
|
||||
msgid "Original geocache location"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:381
|
||||
#, php-format
|
||||
msgid "Original (owner-supplied) location of the %s geocache"
|
||||
msgstr ""
|
||||
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:30
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
msgid "hidden by"
|
||||
msgstr "nascosta da"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:64
|
||||
#, php-format
|
||||
msgid "%d recommendation"
|
||||
msgid_plural "%d recommendations"
|
||||
msgstr[0] "%d raccomandazione"
|
||||
msgstr[1] "%d raccomandazioni"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:63
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:65
|
||||
#, php-format
|
||||
msgid "found %d time"
|
||||
msgid_plural "found %d times"
|
||||
msgstr[0] "trovata %d volta"
|
||||
msgstr[1] "trovata %d volte"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:66
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:68
|
||||
#, php-format
|
||||
msgid "%d trackable"
|
||||
msgid_plural "%d trackables"
|
||||
msgstr[0] "%d travel bug"
|
||||
msgstr[1] "%d travel bugs"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:70
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:72
|
||||
msgid "Personal notes"
|
||||
msgstr "Note personali"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:74
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:76
|
||||
msgid "Attributes"
|
||||
msgstr "Attributi"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:78
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:80
|
||||
msgid "Trackables"
|
||||
msgstr "Travel bugs"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:88
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:104
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:90
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:106
|
||||
msgid "Images"
|
||||
msgstr "Immagini"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:111
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:113
|
||||
msgid "Spoilers"
|
||||
msgstr "Spoiler"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:120
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:122
|
||||
msgid "Image descriptions"
|
||||
msgstr "Descrizione immagine"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:128
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:130
|
||||
msgid "The cache probably is located in the following protection areas:"
|
||||
msgstr "La cache probabilmente è situata nelle seguenti aree protette:"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:70
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:70
|
||||
msgid ""
|
||||
"You are trying to publish a log entry with a date in future. Cache log "
|
||||
"entries are allowed to be published in the past, but NOT in the future."
|
||||
@ -117,7 +147,7 @@ msgstr ""
|
||||
"Hai cercato di pubblicare un log con una data nel futuro. E' permsso loggare "
|
||||
"una cache con una data passata, ma NON futura."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:92
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:92
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your cache rating was ignored, because %s does not have a rating "
|
||||
@ -126,7 +156,7 @@ msgstr ""
|
||||
"Tuttavia, la tua valutazione della cache sarà ignorata, perché %s non ha un "
|
||||
"sistema di valutazione."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:111
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:111
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your cache recommendation was ignored, because %s does not allow "
|
||||
@ -135,7 +165,7 @@ msgstr ""
|
||||
"Tuttavia, la tua valutazione della cache sarà ignorata, perché %s non ha "
|
||||
"permette la valutazione di cache evento."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:125
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:125
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
||||
@ -144,7 +174,7 @@ msgstr ""
|
||||
"Tuttavia, la tua segnalazione di \"manutenzione necessaria\" sarà ignorata, "
|
||||
"perché %s non supporta questa opzione."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:145
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:145
|
||||
msgid ""
|
||||
"This cache is an Event cache. You cannot \"Find\" it (but you can attend it, "
|
||||
"or comment on it)!"
|
||||
@ -152,7 +182,7 @@ msgstr ""
|
||||
"Questa cache è una cache Evento. Non puoi \"Trovarla\" (ma puoi partecipare, "
|
||||
"o commentare l'evento)!"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:150
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:150
|
||||
msgid ""
|
||||
"This cache is NOT an Event cache. You cannot \"Attend\" it (but you can find "
|
||||
"it, or comment on it)!"
|
||||
@ -160,23 +190,23 @@ msgstr ""
|
||||
"Questa cache NON è una cache Evento. Non puoi \"Partecipare\" (ma puoi "
|
||||
"trovarla, o inserirci un commento)!"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:155
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:155
|
||||
msgid "Your have to supply some text for your comment."
|
||||
msgstr "Devi inserire del testo per il tuo commento."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:168
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:168
|
||||
msgid "This cache requires a password. You didn't provide one!"
|
||||
msgstr "Questa cache richiede una password, ma non ne hai fornita nessuuna."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:170
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:170
|
||||
msgid "Invalid password!"
|
||||
msgstr "Password non valida!"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:282
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:285
|
||||
msgid "You have already submitted a log entry with exactly the same contents."
|
||||
msgstr "Hai già inserito un log esattamente con lo stesso contenuto."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:305
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:308
|
||||
msgid ""
|
||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||
"\"Comments\" only!"
|
||||
@ -184,49 +214,49 @@ msgstr ""
|
||||
"Hai già inserito un log \"Trovata\". Adesso puoi inserire solamente "
|
||||
"\"Commenti\"!"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:307
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:310
|
||||
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||
msgstr "Sei il proprietario della cache. Puoi inserire solamente \"Commenti\"!"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:325
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:328
|
||||
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||
msgstr ""
|
||||
"Hai giàvalutato questa cache. La tua valutazione non può essere cambiata."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:342
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:345
|
||||
msgid "You have already recommended this cache once."
|
||||
msgstr "Hai già raccmandato questa cache."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:352
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:355
|
||||
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||
msgstr ""
|
||||
"Non hai possibilità di dare raccomandazioni. Prima devio trovare altre cache!"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:395
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:398
|
||||
msgid "Event caches cannot \"need maintenance\"."
|
||||
msgstr "Le cache evento non necessitano di manutenzione!"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/logs/submit.php:525
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/logs/submit.php:528
|
||||
msgid "Your cache log entry was posted successfully."
|
||||
msgstr "Il tuo log sulla cache è stato correttamente inserito."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorize.tpl.php:5
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:5
|
||||
msgid "Authorization Form"
|
||||
msgstr "Modulo di autorizzazione"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorize.tpl.php:46
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:46
|
||||
msgid "Expired request"
|
||||
msgstr "Richiesta scaduta"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorize.tpl.php:47
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:47
|
||||
msgid "Unfortunately, the request has expired. Please try again."
|
||||
msgstr "Sfortunatamente, la richiesta è scaduta. Per favore riprova."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorize.tpl.php:49
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:49
|
||||
msgid "External application is requesting access..."
|
||||
msgstr "Una applicazione esterna sta richiedendo l'accesso."
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorize.tpl.php:50
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:50
|
||||
#, php-format
|
||||
msgid ""
|
||||
"<b>%s</b> wants to access your <b>%s</b> account. Do you agree to grant "
|
||||
@ -235,122 +265,118 @@ msgstr ""
|
||||
"<b>%s</b> vuole accedere al tuo account <b>%s</b>. Sei d'accordo nel "
|
||||
"concedere l'accesso a questa applicazione?"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorize.tpl.php:53
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:53
|
||||
msgid "I agree"
|
||||
msgstr "Sono d'accordo"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorize.tpl.php:54
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:54
|
||||
msgid "Decline"
|
||||
msgstr "No"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorize.tpl.php:56
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorize.tpl.php:56
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
||||
"OKAPI Framework</a>.\n"
|
||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
||||
"methods delivered\n"
|
||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
||||
"name.\n"
|
||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>Once permission is granted it is valid until its "
|
||||
"withdrawal on\n"
|
||||
" the <a href='%s'>applications management</a> page.</p>\n"
|
||||
" <p>The application will access your acount via <a "
|
||||
"href='%s'>the OKAPI Framework</a>.\n"
|
||||
" If you allow this request application will be able to "
|
||||
"access all methods delivered\n"
|
||||
" by the OKAPI Framework, i.e. post log entries on "
|
||||
"geocaches in your name.\n"
|
||||
" You can revoke this permission at any moment.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Una volta concessa, l'autorizzazoine è valida finché non venga\n"
|
||||
"\t\t\t\t\trevocata nella pagina di <a href='%s'>gestione applicazioni</a>.</"
|
||||
"p>\n"
|
||||
"\t\t\t\t\t<p>L'applicazione accederà al tuo account tramite il <a "
|
||||
"href='%s'>frameword OKAPI</a>.\n"
|
||||
"\t\t\t\t\tSe permetti questa richiesta, l'applicazione potrà accedere a "
|
||||
"tutti i metodi forniti\n"
|
||||
"\t\t\t\t\tdal framework OKAPI, per es. postare i log delle geocache a tuo "
|
||||
"nome..\n"
|
||||
"\t\t\t\t\tPuoi revocare questo permesso in qualsiasi momento.</p>\n"
|
||||
"\t\t\t\t"
|
||||
"<p>Una volta concessa, l'autorizzazoine è valida finché non venga\n"
|
||||
"revocata nella pagina di <a href='%s'>gestione applicazioni</a>.</p>\n"
|
||||
"<p>L'applicazione accederà al tuo account tramite il <a href='%s'>frameword "
|
||||
"OKAPI</a>.\n"
|
||||
"Se permetti questa richiesta, l'applicazione potrà accedere a tutti i metodi "
|
||||
"forniti\n"
|
||||
"dal framework OKAPI, per es. postare i log delle geocache a tuo nome..\n"
|
||||
"Puoi revocare questo permesso in qualsiasi momento.</p>"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorized.tpl.php:5
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorized.tpl.php:5
|
||||
msgid "Authorization Succeeded"
|
||||
msgstr "Autorizzazione concessa"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorized.tpl.php:28
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorized.tpl.php:28
|
||||
msgid "Access successfully granted"
|
||||
msgstr "Accesso correttamente consentito"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/authorized.tpl.php:29
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/authorized.tpl.php:29
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
||||
"b>\n"
|
||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
||||
"code:</p>\n"
|
||||
"\t\t\t"
|
||||
" <p><b>You've just granted %s application access to your %s "
|
||||
"account.</b>\n"
|
||||
" To complete the operation, go back to %s and enter the "
|
||||
"following PIN code:</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>Hai appena concesso all'applicazione \"%s\" l'accesso al tuo "
|
||||
"account %s.</b>\n"
|
||||
"\t\t\t\tPer completare l'operazione, riorna a %s e inserisci il seguente "
|
||||
"codice PIN:</p>\n"
|
||||
"\t\t\t"
|
||||
"<p><b>Hai appena concesso all'applicazione \"%s\" l'accesso al tuo account "
|
||||
"%s.</b>\n"
|
||||
"Per completare l'operazione, riorna a %s e inserisci il seguente codice PIN:"
|
||||
"</p>"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/index.tpl.php:5
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:5
|
||||
msgid "My Apps"
|
||||
msgstr "Mie App"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/index.tpl.php:29
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:29
|
||||
msgid "Your external applications"
|
||||
msgstr "Le tue applicazioni esterne"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/index.tpl.php:31
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:31
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
||||
"your <b>%s</b> account.\n"
|
||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
||||
"privileges.\n"
|
||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
||||
"to perform any\n"
|
||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>This is the list of applications which you granted "
|
||||
"access to your <b>%s</b> account.\n"
|
||||
" This page gives you the abbility to revoke all "
|
||||
"previously granted privileges.\n"
|
||||
" Once you click \"remove\" the application will no longer "
|
||||
"be able to perform any\n"
|
||||
" actions on your behalf.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Questa è la lista delle applicazioni a cui hai concesso "
|
||||
"l'accesso al tuo account <b>%s</b.\n"
|
||||
"\t\t\t\t\tQuesta pagina ti da la possibilità di revocare tutti privilegi "
|
||||
"<p>Questa è la lista delle applicazioni a cui hai concesso l'accesso al tuo "
|
||||
"account <b>%s</b.\n"
|
||||
"Questa pagina ti da la possibilità di revocare tutti privilegi "
|
||||
"precedentemente concessi.\n"
|
||||
"\t\t\t\t\tQundo clicchi su \"rimuovi\" all'applicazione non sarà più "
|
||||
"concesso eseguire nessuna\n"
|
||||
" \t\t\t\t\tazione per tuo conto.</p>\n"
|
||||
"\t\t\t\t"
|
||||
"Qundo clicchi su \"rimuovi\" all'applicazione non sarà più concesso eseguire "
|
||||
"nessuna\n"
|
||||
"azione per tuo conto.</p>"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/index.tpl.php:45
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:45
|
||||
msgid "remove"
|
||||
msgstr "entfernen"
|
||||
|
||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/views/apps/index.tpl.php:50
|
||||
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/views/apps/index.tpl.php:50
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
||||
"external applications\n"
|
||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
||||
"authorized to act\n"
|
||||
"\t\t\t\t\ton your behalf. Once you start using external Opencaching "
|
||||
"applications, they will appear here.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>Thanks to the <a href='%s'>OKAPI Framework</a> you "
|
||||
"can grant external applications\n"
|
||||
" access to your <b>%s</b> account. Currently no "
|
||||
"applications are authorized to act\n"
|
||||
" on your behalf. Once you start using external "
|
||||
"Opencaching applications, they will appear here.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Grazie al <a href='%s'>framework OKAPI</a>puoi concedere ad "
|
||||
"applicazioni esterne\n"
|
||||
"\t\t\t\t\t l'accesso al tuo account <b>%s</b>. Attualmente non ci son "
|
||||
"applicazioni autorizzate\n"
|
||||
"\t\t\t\t\tad agire per tuo conto. Quando userai applicazioni esterne a "
|
||||
"Opencaching, queste appariranno qui</p>\n"
|
||||
"\t\t\t\t"
|
||||
"<p>Grazie al <a href='%s'>framework OKAPI</a>puoi concedere ad applicazioni "
|
||||
"esterne\n"
|
||||
"l'accesso al tuo account <b>%s</b>. Attualmente non ci son applicazioni "
|
||||
"autorizzate\n"
|
||||
"ad agire per tuo conto. Quando userai applicazioni esterne a Opencaching, "
|
||||
"queste appariranno qui</p>\n"
|
||||
" "
|
||||
|
||||
#~ msgid "Recommending is allowed only for 'Found it' logtypes."
|
||||
#~ msgstr "Le raccomandazioni sono ammesse solo per i log di tipo 'Trovata'"
|
||||
|
@ -4,53 +4,53 @@ namespace okapi;
|
||||
|
||||
class Locales
|
||||
{
|
||||
public static $languages = array(
|
||||
'pl' => array('lang' => 'pl', 'locale' => 'pl_PL.utf8', 'name' => 'Polish'),
|
||||
'en' => array('lang' => 'en', 'locale' => 'en_US.utf8', 'name' => 'English'),
|
||||
'nl' => array('lang' => 'nl', 'locale' => 'nl_NL.utf8', 'name' => 'Dutch'),
|
||||
'de' => array('lang' => 'de', 'locale' => 'de_DE.utf8', 'name' => 'German'),
|
||||
'it' => array('lang' => 'it', 'locale' => 'it_IT.utf8', 'name' => 'Italian'),
|
||||
);
|
||||
public static $languages = array(
|
||||
'pl' => array('lang' => 'pl', 'locale' => 'pl_PL.utf8', 'name' => 'Polish'),
|
||||
'en' => array('lang' => 'en', 'locale' => 'en_US.utf8', 'name' => 'English'),
|
||||
'nl' => array('lang' => 'nl', 'locale' => 'nl_NL.utf8', 'name' => 'Dutch'),
|
||||
'de' => array('lang' => 'de', 'locale' => 'de_DE.utf8', 'name' => 'German'),
|
||||
'it' => array('lang' => 'it', 'locale' => 'it_IT.utf8', 'name' => 'Italian'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the list of locales that should be installed on the system in order
|
||||
* for all translations to work properly.
|
||||
*/
|
||||
public static function get_required_locales()
|
||||
{
|
||||
$arr = array('POSIX');
|
||||
foreach (self::$languages as $key => $value)
|
||||
$arr[] = $value['locale'];
|
||||
return $arr;
|
||||
}
|
||||
/**
|
||||
* Get the list of locales that should be installed on the system in order
|
||||
* for all translations to work properly.
|
||||
*/
|
||||
public static function get_required_locales()
|
||||
{
|
||||
$arr = array('POSIX');
|
||||
foreach (self::$languages as $key => $value)
|
||||
$arr[] = $value['locale'];
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of locales installed on the current system.
|
||||
*/
|
||||
public static function get_installed_locales()
|
||||
{
|
||||
$arr = array();
|
||||
foreach (explode("\n", shell_exec("locale -a")) as $item)
|
||||
if ($item)
|
||||
$arr[] = $item;
|
||||
return $arr;
|
||||
}
|
||||
/**
|
||||
* Get the list of locales installed on the current system.
|
||||
*/
|
||||
public static function get_installed_locales()
|
||||
{
|
||||
$arr = array();
|
||||
foreach (explode("\n", shell_exec("locale -a")) as $item)
|
||||
if ($item)
|
||||
$arr[] = $item;
|
||||
return $arr;
|
||||
}
|
||||
|
||||
private static function get_locale_for_language($lang)
|
||||
{
|
||||
if (isset(self::$languages[$lang]))
|
||||
return self::$languages[$lang]['locale'];
|
||||
return null;
|
||||
}
|
||||
private static function get_locale_for_language($lang)
|
||||
{
|
||||
if (isset(self::$languages[$lang]))
|
||||
return self::$languages[$lang]['locale'];
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function get_best_locale($langprefs)
|
||||
{
|
||||
foreach ($langprefs as $lang)
|
||||
{
|
||||
$locale = self::get_locale_for_language($lang);
|
||||
if ($locale != null)
|
||||
return $locale;
|
||||
}
|
||||
return self::$languages['en']['locale'];
|
||||
}
|
||||
public static function get_best_locale($langprefs)
|
||||
{
|
||||
foreach ($langprefs as $lang)
|
||||
{
|
||||
$locale = self::get_locale_for_language($lang);
|
||||
if ($locale != null)
|
||||
return $locale;
|
||||
}
|
||||
return self::$languages['en']['locale'];
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@ -2,9 +2,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OKAPI\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-04-10 01:08+0100\n"
|
||||
"PO-Revision-Date: 2013-04-10 01:12+0100\n"
|
||||
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
||||
"POT-Creation-Date: 2014-01-23 16:05+0100\n"
|
||||
"PO-Revision-Date: 2014-08-09 03:47+0100\n"
|
||||
"Last-Translator: Harrie Klomp <harrie@harrieklomp.be>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: nl_NL\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -13,50 +13,96 @@ msgstr ""
|
||||
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
|
||||
"X-Poedit-Basepath: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api\\\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 1.5.5\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
# For additional waypoints. As in "Stage 1: Parking".
|
||||
#: okapi/services/caches/geocaches.php:846
|
||||
#: okapi/services/caches/geocaches.php:957
|
||||
msgid "Stage"
|
||||
msgstr "Etappe"
|
||||
|
||||
#: okapi/services/caches/geocaches.php:1009
|
||||
#: okapi/services/caches/geocaches.php:986
|
||||
msgid "User location"
|
||||
msgstr "Gebruikers locatie"
|
||||
|
||||
#: okapi/services/caches/geocaches.php:989
|
||||
#, php-format
|
||||
msgid "Your own custom coordinates for the %s geocache"
|
||||
msgstr "Eigen gecorrigeerde coördinaten voor %s geocache"
|
||||
|
||||
#: okapi/services/caches/geocaches.php:1148
|
||||
msgid "National Park / Landscape"
|
||||
msgstr "Nationaal park / Landschap"
|
||||
|
||||
#: okapi/services/caches/geocaches.php:1300
|
||||
#, php-format
|
||||
msgid ""
|
||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||
"a> site."
|
||||
msgstr ""
|
||||
"Deze <a href='%s'>geocache</a> beschrijving komt van de <a href='%s'>%s</a> "
|
||||
"\"\"site."
|
||||
|
||||
#: okapi/services/caches/geocaches.php:1021
|
||||
#, php-format
|
||||
#: okapi/services/caches/geocaches.php:1312
|
||||
#, fuzzy, php-format
|
||||
msgid ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/de/deed.en'>CC-BY-NC-ND</a>, as of "
|
||||
"%s; all log entries © their authors"
|
||||
msgstr ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/nl/deed.en'>CC-BY-NC-ND</a>, as of "
|
||||
"%s; all log entries © their authors"
|
||||
|
||||
#: okapi/services/caches/geocaches.php:1032
|
||||
#, php-format
|
||||
#: okapi/services/caches/geocaches.php:1323
|
||||
#, fuzzy, php-format
|
||||
msgid ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/de/deed.en'>CC-BY-NC-ND</a>; all "
|
||||
"log entries © their authors"
|
||||
msgstr ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/nl/deed.en'>CC-BY-NC-ND</a>; all "
|
||||
"log entries © their authors"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:31
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:48
|
||||
#: okapi/services/caches/formatters/gpx.php:360
|
||||
msgid ""
|
||||
"<b>Geocache coordinates have been changed.</b> They have been replaced with "
|
||||
"your own custom coordinates which you have provided for this geocache."
|
||||
msgstr ""
|
||||
"Geocache coördinaten zijn veranderd.</b> Deze zijn aangepast door "
|
||||
"coördinaten die je zelf hebt gewijzigd voor deze geocache."
|
||||
|
||||
#: okapi/services/caches/formatters/gpx.php:366
|
||||
msgid ""
|
||||
"<b>Geocache coordinates have been changed.</b> Currently they point to one "
|
||||
"of the alternate waypoints originally described as:"
|
||||
msgstr ""
|
||||
"Geocache coördinaten zijn veranderd.</b> Momenteel wijzen zij een van de "
|
||||
"alternatieve waypoints oorspronkelijk beschreven als:"
|
||||
|
||||
#: okapi/services/caches/formatters/gpx.php:379
|
||||
msgid "Original geocache location"
|
||||
msgstr "Orginele geocache locatie"
|
||||
|
||||
#: okapi/services/caches/formatters/gpx.php:381
|
||||
#, php-format
|
||||
msgid "Original (owner-supplied) location of the %s geocache"
|
||||
msgstr "Originele (opgegeven door plaatser) locatie van de %s geocache"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:30
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
msgid "hidden by"
|
||||
msgstr "geplaatst door"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:50
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:64
|
||||
#, php-format
|
||||
msgid "%d recommendation"
|
||||
msgid_plural "%d recommendations"
|
||||
msgstr[0] "%d aanbeveling"
|
||||
msgstr[1] "%d aanbevelingen"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:51
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:65
|
||||
#, php-format
|
||||
msgid "found %d time"
|
||||
msgid_plural "found %d times"
|
||||
@ -64,37 +110,42 @@ msgstr[0] "%d keer gevonden"
|
||||
msgstr[1] "%d keren gevonden"
|
||||
|
||||
# Generic term for trackable items (like geocoins and travelbugs).
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:54
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:68
|
||||
#, php-format
|
||||
msgid "%d trackable"
|
||||
msgid_plural "%d trackables"
|
||||
msgstr[0] "%d trackable"
|
||||
msgstr[1] "%d trackables"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:58
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:72
|
||||
msgid "Personal notes"
|
||||
msgstr "Persoonlijke notities"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:76
|
||||
msgid "Attributes"
|
||||
msgstr "Attributen"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:66
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:80
|
||||
msgid "Trackables"
|
||||
msgstr "Trackables"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:84
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:90
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:106
|
||||
msgid "Images"
|
||||
msgstr "Afbeeldingen"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:91
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:113
|
||||
msgid "Spoilers"
|
||||
msgstr "Spoilers"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:99
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:122
|
||||
msgid "Image descriptions"
|
||||
msgstr "Afbeelding omschrijving"
|
||||
|
||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:130
|
||||
msgid "The cache probably is located in the following protection areas:"
|
||||
msgstr "De cache is waarschijnlijk in een volgend beschermd gebied geplaatst:"
|
||||
|
||||
#: okapi/services/logs/submit.php:70
|
||||
msgid ""
|
||||
"You are trying to publish a log entry with a date in future. Cache log "
|
||||
@ -112,40 +163,59 @@ msgstr ""
|
||||
"De cachewaardering is genegeerd, omdat %s geen waarderingen in het systeem "
|
||||
"heeft."
|
||||
|
||||
#: okapi/services/logs/submit.php:113
|
||||
#: okapi/services/logs/submit.php:111
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your cache recommendation was ignored, because %s does not allow "
|
||||
"recommending event caches."
|
||||
msgstr ""
|
||||
"De cachewaardering is genegeerd, omdat %s geen waarderingen op evenementen "
|
||||
"ondersteund."
|
||||
|
||||
#: okapi/services/logs/submit.php:125
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
||||
"support this feature."
|
||||
msgstr ""
|
||||
"Maar jouw \"Heeft onderhoud nodig\" log is genegeerd omdat %s dit niet "
|
||||
"ondersteunt."
|
||||
|
||||
# The user will see this error when he is trying to submit a "Fount it" entry on an event cache. "Attended" or "Will attend" log entries are not the same as "Found it". Currently OKAPI does not allow to submit "Attended" nor "Will attend" log entries, that's why user can only "Comment" on it.
|
||||
#: okapi/services/logs/submit.php:131
|
||||
# Missing "you can attend it"
|
||||
#: okapi/services/logs/submit.php:145
|
||||
msgid ""
|
||||
"This cache is an Event cache. You cannot \"Find it\"! (But - you may "
|
||||
"\"Comment\" on it.)"
|
||||
"This cache is an Event cache. You cannot \"Find\" it (but you can attend it, "
|
||||
"or comment on it)!"
|
||||
msgstr ""
|
||||
"Dit is een eventcache. Deze kan niet als \"Gevonden\" gelogd worden. Maar "
|
||||
"wel als \"Notitie\"."
|
||||
"Dit is een evenement. Deze kan niet als \"Gevonden\" gelogd worden. (maar "
|
||||
"wel deelgenomen of een notitie plaatsen)."
|
||||
|
||||
#: okapi/services/logs/submit.php:133
|
||||
#: okapi/services/logs/submit.php:150
|
||||
msgid ""
|
||||
"This cache is NOT an Event cache. You cannot \"Attend\" it (but you can find "
|
||||
"it, or comment on it)!"
|
||||
msgstr ""
|
||||
"Deze cache is GEEN evenement. Je kunt niet \"Deelnemen\" (maar wel als "
|
||||
"gevonden loggen of een notitie plaatsen)"
|
||||
|
||||
#: okapi/services/logs/submit.php:155
|
||||
msgid "Your have to supply some text for your comment."
|
||||
msgstr "Er dient enige tekst ingevuld te worden."
|
||||
|
||||
#: okapi/services/logs/submit.php:146
|
||||
#: okapi/services/logs/submit.php:168
|
||||
msgid "This cache requires a password. You didn't provide one!"
|
||||
msgstr "Deze cache vraagt om een wachtwoord. Deze is niet opgegeven!"
|
||||
|
||||
#: okapi/services/logs/submit.php:148
|
||||
#: okapi/services/logs/submit.php:170
|
||||
msgid "Invalid password!"
|
||||
msgstr "Verkeerd wachtwoord!"
|
||||
|
||||
# This error will be shown to the user when he tries to submit a log entry which is EXACTLY the same as one he had submitted before.
|
||||
#: okapi/services/logs/submit.php:260
|
||||
#: okapi/services/logs/submit.php:285
|
||||
msgid "You have already submitted a log entry with exactly the same contents."
|
||||
msgstr "Deze log is reeds met dezelfde tekst verzonden."
|
||||
|
||||
#: okapi/services/logs/submit.php:279
|
||||
#: okapi/services/logs/submit.php:308
|
||||
msgid ""
|
||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||
"\"Comments\" only!"
|
||||
@ -153,25 +223,29 @@ msgstr ""
|
||||
"Je hebt deze cache al als \"Gevonden\" gelogd. Je kunt nu wel een \"Notitie"
|
||||
"\" plaatsen."
|
||||
|
||||
# The English text was changed from "you cannot rate it" to "you cannot find it". The translation remained.
|
||||
#: okapi/services/logs/submit.php:281
|
||||
#: okapi/services/logs/submit.php:310
|
||||
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||
msgstr ""
|
||||
"Je bent eigenaar van deze cache. Je kunt alleen een \"Notitie\" plaatsen."
|
||||
|
||||
#: okapi/services/logs/submit.php:299
|
||||
#: okapi/services/logs/submit.php:328
|
||||
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||
msgstr ""
|
||||
"Je hebt deze cache al gewaardeerd. De waardering kan niet veranderd worden."
|
||||
|
||||
#: okapi/services/logs/submit.php:316
|
||||
#: okapi/services/logs/submit.php:345
|
||||
msgid "You have already recommended this cache once."
|
||||
msgstr ""
|
||||
msgstr "Je hebt al een aanbeveling op deze cache gegeven."
|
||||
|
||||
#: okapi/services/logs/submit.php:323
|
||||
#: okapi/services/logs/submit.php:355
|
||||
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||
msgstr ""
|
||||
msgstr "Je kunt geen aanbeveling meer geven. Vind eerst meer caches."
|
||||
|
||||
#: okapi/services/logs/submit.php:491
|
||||
#: okapi/services/logs/submit.php:398
|
||||
msgid "Event caches cannot \"need maintenance\"."
|
||||
msgstr "Evenementen hebben geen \"onderhoud nodig"
|
||||
|
||||
#: okapi/services/logs/submit.php:528
|
||||
msgid "Your cache log entry was posted successfully."
|
||||
msgstr "De log is succesvol verzonden."
|
||||
|
||||
@ -208,35 +282,33 @@ msgstr "Toestemmen"
|
||||
msgid "Decline"
|
||||
msgstr "Afwijzen"
|
||||
|
||||
# This should begin with "\n", but you may ignore the rest of \n and \r characters.
|
||||
# This should begin with "\n", but you may ignore the rest of \n characters.
|
||||
# This message is shown to the user when external application is trying to get user's permission to access his account.
|
||||
# Sample: http://i.imgur.com/ZCJNT.png
|
||||
#: okapi/views/apps/authorize.tpl.php:56
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
||||
"OKAPI Framework</a>.\n"
|
||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
||||
"methods delivered\n"
|
||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
||||
"name.\n"
|
||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>Once permission is granted it is valid until its "
|
||||
"withdrawal on\n"
|
||||
" the <a href='%s'>applications management</a> page.</p>\n"
|
||||
" <p>The application will access your acount via <a "
|
||||
"href='%s'>the OKAPI Framework</a>.\n"
|
||||
" If you allow this request application will be able to "
|
||||
"access all methods delivered\n"
|
||||
" by the OKAPI Framework, i.e. post log entries on "
|
||||
"geocaches in your name.\n"
|
||||
" You can revoke this permission at any moment.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Wanneer toegestemd is blijft deze geldig tot intrekking op\n"
|
||||
"\t\t\t\t\tde <a href='%s'>toepassingsbeheer</a> pagina.</p>\n"
|
||||
"\t\t\t\t\t<p>De toepassing zal toegang krijgen via jouw account op <a "
|
||||
"href='%s'>the OKAPI Framework</a>.\n"
|
||||
"\t\t\t\t\tWanneer je toestemming geeft voor deze toepassing zullen de "
|
||||
"mogelijkheden\n"
|
||||
"\t\t\t\t\tvan OKAPI Framework toegepast worden, b.v. het loggen van een "
|
||||
"cache.\n"
|
||||
"\t\t\t\t\tDe toestemming kan elk moment ingetrokken worden.</p>\n"
|
||||
"\t\t\t\t"
|
||||
"<p>Wanneer toegestemd is blijft deze geldig tot intrekking op\n"
|
||||
"de <a href='%s'>toepassingsbeheer</a> pagina.</p>\n"
|
||||
"<p>De toepassing zal toegang krijgen via jouw account op <a href='%s'>the "
|
||||
"OKAPI Framework</a>.\n"
|
||||
"Wanneer je toestemming geeft voor deze toepassing zullen de mogelijkheden\n"
|
||||
"van OKAPI Framework toegepast worden, b.v. het loggen van een cache.\n"
|
||||
"De toestemming kan elk moment ingetrokken worden.</p>"
|
||||
|
||||
#: okapi/views/apps/authorized.tpl.php:5
|
||||
msgid "Authorization Succeeded"
|
||||
@ -251,18 +323,16 @@ msgstr "Met succes toegang verleend"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
||||
"b>\n"
|
||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
||||
"code:</p>\n"
|
||||
"\t\t\t"
|
||||
" <p><b>You've just granted %s application access to your %s "
|
||||
"account.</b>\n"
|
||||
" To complete the operation, go back to %s and enter the "
|
||||
"following PIN code:</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>Je hebt toegang verleent voor %s toepassing op jouw %s account."
|
||||
"</b>\n"
|
||||
"\t\t\t\tOm de aktie te voltooien, ga terug naar %s en gebruik de volgende "
|
||||
"PIN code:</p>\n"
|
||||
"\t\t\t"
|
||||
"<p><b>Je hebt toegang verleent voor %s toepassing op jouw %s account.</b>\n"
|
||||
"Om de actie te voltooien, ga terug naar %s en gebruik de volgende PIN code:</"
|
||||
"p>"
|
||||
|
||||
#: okapi/views/apps/index.tpl.php:5
|
||||
msgid "My Apps"
|
||||
@ -273,29 +343,25 @@ msgid "Your external applications"
|
||||
msgstr "Jouw externe toepassingen"
|
||||
|
||||
# This will be shown when user visits /okapi/apps page.
|
||||
# Sample: http://i.imgur.com/ZCJNT.png
|
||||
#: okapi/views/apps/index.tpl.php:31
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
||||
"your <b>%s</b> account.\n"
|
||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
||||
"privileges.\n"
|
||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
||||
"to perform any\n"
|
||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>This is the list of applications which you granted "
|
||||
"access to your <b>%s</b> account.\n"
|
||||
" This page gives you the abbility to revoke all "
|
||||
"previously granted privileges.\n"
|
||||
" Once you click \"remove\" the application will no longer "
|
||||
"be able to perform any\n"
|
||||
" actions on your behalf.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Dit is een lijst met toegestane toepassingen op jouw <b>%s</b> "
|
||||
"account.\n"
|
||||
"\t\t\t\t\tOp deze pagina kun je alle toestemmingen intrekken die gegeven "
|
||||
"zijn.\n"
|
||||
"\t\t\t\t\tMet een klik op \"verwijderen\" zal de toepassing verwijderen en "
|
||||
"is dan ook niet meer beschikbaar\n"
|
||||
"\t\t\t\t\voor anderen.</p>\n"
|
||||
"\t\t\t\t"
|
||||
"<p>Dit is een lijst met toegestane toepassingen op jouw <b>%s</b> account.\n"
|
||||
"Op deze pagina kun je alle toestemmingen intrekken die gegeven zijn.\n"
|
||||
"Met een klik op \"verwijderen\" zal de toepassing verwijderen en is dan ook "
|
||||
"niet meer beschikbaar\n"
|
||||
"oor anderen.</p>"
|
||||
|
||||
#: okapi/views/apps/index.tpl.php:45
|
||||
msgid "remove"
|
||||
@ -305,22 +371,21 @@ msgstr "verwijderen"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
||||
"external applications\n"
|
||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
||||
"authorized to act\n"
|
||||
"\t\t\t\t\ton your behalf. Once you start using external Opencaching "
|
||||
"applications, they will appear here.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>Thanks to the <a href='%s'>OKAPI Framework</a> you "
|
||||
"can grant external applications\n"
|
||||
" access to your <b>%s</b> account. Currently no "
|
||||
"applications are authorized to act\n"
|
||||
" on your behalf. Once you start using external "
|
||||
"Opencaching applications, they will appear here.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Dankzij het <a href='%s'>OKAPI Framework</a> kun je toegang "
|
||||
"verlenen via externe\n"
|
||||
"\t\t\t\t\ttoepassingen op een <b>%s</b> account. Momenteel zijn op dit "
|
||||
"account nog geen externe\n"
|
||||
"\t\t\t\t\ttoepassingen actief. Geactiveerde Opencaching toepassingen "
|
||||
"zullen hier getoond worden.</p>\n"
|
||||
"\t\t\t\t"
|
||||
"<p>Dankzij het <a href='%s'>OKAPI Framework</a> kun je toegang verlenen via "
|
||||
"externe\n"
|
||||
"toepassingen op een <b>%s</b> account. Momenteel zijn op dit account nog "
|
||||
"geen externe\n"
|
||||
"toepassingen actief. Geactiveerde Opencaching toepassingen zullen hier "
|
||||
"getoond worden.</p>"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "This cache is archived. Only admins and the owner are allowed to add a "
|
||||
|
Binary file not shown.
@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OKAPI\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-07-11 08:28+0100\n"
|
||||
"PO-Revision-Date: 2013-07-11 08:35+0100\n"
|
||||
"POT-Creation-Date: 2014-01-23 15:48+0100\n"
|
||||
"PO-Revision-Date: 2014-01-23 15:49+0100\n"
|
||||
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: pl_PL\n"
|
||||
@ -15,26 +15,35 @@ msgstr ""
|
||||
"\\okapi\n"
|
||||
"Plural-Forms: nplurals=3; plural= n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2;\n"
|
||||
"X-Poedit-SourceCharset: utf-8\n"
|
||||
"X-Generator: Poedit 1.5.5\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Generator: Poedit 1.6.3\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: services/caches/geocaches.php:956
|
||||
#: services/caches/geocaches.php:957
|
||||
msgid "Stage"
|
||||
msgstr "Etap"
|
||||
|
||||
#: services/caches/geocaches.php:1111
|
||||
#: services/caches/geocaches.php:986
|
||||
msgid "User location"
|
||||
msgstr "Współrzędne użytkownika"
|
||||
|
||||
#: services/caches/geocaches.php:989
|
||||
#, php-format
|
||||
msgid "Your own custom coordinates for the %s geocache"
|
||||
msgstr "Twoje osobiste współrzędne skrzynki %s"
|
||||
|
||||
#: services/caches/geocaches.php:1148
|
||||
msgid "National Park / Landscape"
|
||||
msgstr "Park narodowy lub krajobrazowy"
|
||||
|
||||
#: services/caches/geocaches.php:1263
|
||||
#: services/caches/geocaches.php:1300
|
||||
#, php-format
|
||||
msgid ""
|
||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||
"a> site."
|
||||
msgstr "Opis <a href='%s'>skrzynki</a> pochodzi z serwisu <a href='%s'>%s</a>."
|
||||
|
||||
#: services/caches/geocaches.php:1275
|
||||
#: services/caches/geocaches.php:1312
|
||||
#, php-format
|
||||
msgid ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
@ -45,7 +54,7 @@ msgstr ""
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/de/deed.pl'>CC-BY-NC-ND</a>, w "
|
||||
"dniu %s. Prawa autorskie wpisów do logów należą do ich autorów."
|
||||
|
||||
#: services/caches/geocaches.php:1286
|
||||
#: services/caches/geocaches.php:1323
|
||||
#, php-format
|
||||
msgid ""
|
||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
@ -56,12 +65,37 @@ msgstr ""
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/de/deed.pl'>CC-BY-NC-ND</a>. Prawa "
|
||||
"autorskie wpisów do logów należą do ich autorów."
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:31
|
||||
#: services/caches/formatters/gpxfile.tpl.php:60
|
||||
#: services/caches/formatters/gpx.php:360
|
||||
msgid ""
|
||||
"<b>Geocache coordinates have been changed.</b> They have been replaced with "
|
||||
"your own custom coordinates which you have provided for this geocache."
|
||||
msgstr ""
|
||||
"<b>Współrzędne skrzynki zostały zmienione.</b> Zostały zastąpione Twoimi "
|
||||
"osobistymi współrzędnymi, które wprowadziłeś na stronie tej skrzynki."
|
||||
|
||||
#: services/caches/formatters/gpx.php:366
|
||||
msgid ""
|
||||
"<b>Geocache coordinates have been changed.</b> Currently they point to one "
|
||||
"of the alternate waypoints originally described as:"
|
||||
msgstr ""
|
||||
"<b>Współrzędne skrzynki zostały zmienione.</b> Aktualnie wskazują one na "
|
||||
"jeden z dodatkowych waypointów, oryginalnie opisanego jako:"
|
||||
|
||||
#: services/caches/formatters/gpx.php:379
|
||||
msgid "Original geocache location"
|
||||
msgstr "Oryginalne współrzędne skrzynki"
|
||||
|
||||
#: services/caches/formatters/gpx.php:381
|
||||
#, php-format
|
||||
msgid "Original (owner-supplied) location of the %s geocache"
|
||||
msgstr "Oryginalne współrzędne skrzynki %s (podane przez autora)"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:30
|
||||
#: services/caches/formatters/gpxfile.tpl.php:62
|
||||
msgid "hidden by"
|
||||
msgstr "ukryta przez"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:62
|
||||
#: services/caches/formatters/gpxfile.tpl.php:64
|
||||
#, php-format
|
||||
msgid "%d recommendation"
|
||||
msgid_plural "%d recommendations"
|
||||
@ -69,7 +103,7 @@ msgstr[0] "%d rekomendacja"
|
||||
msgstr[1] "%d rekomendacje"
|
||||
msgstr[2] "%d rekomendacji"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:63
|
||||
#: services/caches/formatters/gpxfile.tpl.php:65
|
||||
#, php-format
|
||||
msgid "found %d time"
|
||||
msgid_plural "found %d times"
|
||||
@ -77,7 +111,7 @@ msgstr[0] "znaleziona %d raz"
|
||||
msgstr[1] "znaleziona %d razy"
|
||||
msgstr[2] "znaleziona %d razy"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:66
|
||||
#: services/caches/formatters/gpxfile.tpl.php:68
|
||||
#, php-format
|
||||
msgid "%d trackable"
|
||||
msgid_plural "%d trackables"
|
||||
@ -85,32 +119,32 @@ msgstr[0] "%d GeoKret (lub TravelBug)"
|
||||
msgstr[1] "%d GeoKrety (lub TravelBugi)"
|
||||
msgstr[2] "%d GeoKretów (lub TravelBugów)"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:70
|
||||
#: services/caches/formatters/gpxfile.tpl.php:72
|
||||
msgid "Personal notes"
|
||||
msgstr "Osobiste notatki"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:74
|
||||
#: services/caches/formatters/gpxfile.tpl.php:76
|
||||
msgid "Attributes"
|
||||
msgstr "Atrybuty"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:78
|
||||
#: services/caches/formatters/gpxfile.tpl.php:80
|
||||
msgid "Trackables"
|
||||
msgstr "Geokrety, Travelbugi itp."
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:88
|
||||
#: services/caches/formatters/gpxfile.tpl.php:104
|
||||
#: services/caches/formatters/gpxfile.tpl.php:90
|
||||
#: services/caches/formatters/gpxfile.tpl.php:106
|
||||
msgid "Images"
|
||||
msgstr "Obrazki"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:111
|
||||
#: services/caches/formatters/gpxfile.tpl.php:113
|
||||
msgid "Spoilers"
|
||||
msgstr "Spoilery"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:120
|
||||
#: services/caches/formatters/gpxfile.tpl.php:122
|
||||
msgid "Image descriptions"
|
||||
msgstr "Opisy obrazków"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:128
|
||||
#: services/caches/formatters/gpxfile.tpl.php:130
|
||||
msgid "The cache probably is located in the following protection areas:"
|
||||
msgstr "Prawdopodobnie skrzynka znajduje się na terenie obszarów chronionych:"
|
||||
|
||||
@ -177,11 +211,11 @@ msgstr "Ta skrzynka wymaga podania hasła. Nie wpisałeś go."
|
||||
msgid "Invalid password!"
|
||||
msgstr "Niepoprawne hasło!"
|
||||
|
||||
#: services/logs/submit.php:282
|
||||
#: services/logs/submit.php:285
|
||||
msgid "You have already submitted a log entry with exactly the same contents."
|
||||
msgstr "Już opublikowałeś wcześniej wpis z dokładnie taką samą treścią."
|
||||
|
||||
#: services/logs/submit.php:305
|
||||
#: services/logs/submit.php:308
|
||||
msgid ""
|
||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||
"\"Comments\" only!"
|
||||
@ -189,30 +223,30 @@ msgstr ""
|
||||
"Już opublikowałeś jeden wpis typu \"Znaleziona\" dla tej skrzynki. Teraz "
|
||||
"możesz dodawać jedynie \"Komentarze\"!"
|
||||
|
||||
#: services/logs/submit.php:307
|
||||
#: services/logs/submit.php:310
|
||||
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||
msgstr ""
|
||||
"Jesteś właścicielem tej skrzynki. Możesz przesyłać jedynie \"Komentarze\"."
|
||||
|
||||
#: services/logs/submit.php:325
|
||||
#: services/logs/submit.php:328
|
||||
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||
msgstr "Już oceniłeś tę skrzynkę. Ocena nie może być zmieniona."
|
||||
|
||||
#: services/logs/submit.php:342
|
||||
#: services/logs/submit.php:345
|
||||
msgid "You have already recommended this cache once."
|
||||
msgstr "Już raz zarekomendowałeś tę skrzynkę."
|
||||
|
||||
#: services/logs/submit.php:352
|
||||
#: services/logs/submit.php:355
|
||||
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||
msgstr ""
|
||||
"Aktualnie nie możesz wystawić kolejnej rekomendacji. Znajdź najpierw więcej "
|
||||
"skrzynek!"
|
||||
|
||||
#: services/logs/submit.php:395
|
||||
#: services/logs/submit.php:398
|
||||
msgid "Event caches cannot \"need maintenance\"."
|
||||
msgstr "Skrzynki typu Wydarzenie nie mogą \"potrzebować serwisu\"."
|
||||
|
||||
#: services/logs/submit.php:525
|
||||
#: services/logs/submit.php:528
|
||||
msgid "Your cache log entry was posted successfully."
|
||||
msgstr "Twój wpis do logbooka został opublikowany pomyślnie."
|
||||
|
||||
@ -253,16 +287,17 @@ msgstr "Odmawiam"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
||||
"OKAPI Framework</a>.\n"
|
||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
||||
"methods delivered\n"
|
||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
||||
"name.\n"
|
||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>Once permission is granted it is valid until its "
|
||||
"withdrawal on\n"
|
||||
" the <a href='%s'>applications management</a> page.</p>\n"
|
||||
" <p>The application will access your acount via <a "
|
||||
"href='%s'>the OKAPI Framework</a>.\n"
|
||||
" If you allow this request application will be able to "
|
||||
"access all methods delivered\n"
|
||||
" by the OKAPI Framework, i.e. post log entries on "
|
||||
"geocaches in your name.\n"
|
||||
" You can revoke this permission at any moment.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p>Raz udzielona zgoda jest ważna aż do momentu jej wycofania na stronie <a "
|
||||
@ -285,11 +320,11 @@ msgstr "Pomyślnie dałeś dostęp"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
||||
"b>\n"
|
||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
||||
"code:</p>\n"
|
||||
"\t\t\t"
|
||||
" <p><b>You've just granted %s application access to your %s "
|
||||
"account.</b>\n"
|
||||
" To complete the operation, go back to %s and enter the "
|
||||
"following PIN code:</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p><b>Właśnie dałeś dostęp aplikacji %s do Twojego konta %s.</b>\n"
|
||||
@ -308,14 +343,14 @@ msgstr "Twoje zewnętrzne aplikacje"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
||||
"your <b>%s</b> account.\n"
|
||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
||||
"privileges.\n"
|
||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
||||
"to perform any\n"
|
||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>This is the list of applications which you granted "
|
||||
"access to your <b>%s</b> account.\n"
|
||||
" This page gives you the abbility to revoke all "
|
||||
"previously granted privileges.\n"
|
||||
" Once you click \"remove\" the application will no longer "
|
||||
"be able to perform any\n"
|
||||
" actions on your behalf.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p>Następującym aplikacjom zezwoliłeś na dostęp do swojego konta <b>%s</b>.\n"
|
||||
@ -332,13 +367,13 @@ msgstr "usuń"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
||||
"external applications\n"
|
||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
||||
"authorized to act\n"
|
||||
"\t\t\t\t\ton your behalf. Once you start using external Opencaching "
|
||||
"applications, they will appear here.</p>\n"
|
||||
"\t\t\t\t"
|
||||
" <p>Thanks to the <a href='%s'>OKAPI Framework</a> you "
|
||||
"can grant external applications\n"
|
||||
" access to your <b>%s</b> account. Currently no "
|
||||
"applications are authorized to act\n"
|
||||
" on your behalf. Once you start using external "
|
||||
"Opencaching applications, they will appear here.</p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p>Dzięki platformie <a href='%s'>OKAPI</a> możesz dawać zewnętrznym "
|
||||
@ -348,6 +383,30 @@ msgstr ""
|
||||
"w Twoim imieniu. Gdy zaczniesz korzystać z zewnętrznych aplikacji, ich lista "
|
||||
"pojawi się tutaj.</p>"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "\n"
|
||||
#~ "\t\t\t\t\t\t\t\t<b>Warning: Changed coordinates.</b> These are not the "
|
||||
#~ "original\n"
|
||||
#~ "\t\t\t\t\t\t\t\tcoordinates of this geocache (as supplied by the owner). "
|
||||
#~ "They\n"
|
||||
#~ "\t\t\t\t\t\t\t\thave been replaced with other coordinates:\n"
|
||||
#~ "\t\t\t\t\t\t\t"
|
||||
#~ msgstr ""
|
||||
#~ "\n"
|
||||
#~ "<b>Uwaga: Zmienione współrzędne.</b> To nie są oryginalne współrzędne tej "
|
||||
#~ "skrzynki (takie, jakie podał jej autor). Współrzędne zostały nadpisane "
|
||||
#~ "innymi współrzędnymi:"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "<b>Geocache's coordinates has been changed</b> to point to the user "
|
||||
#~ "supplied value."
|
||||
#~ msgstr ""
|
||||
#~ "<b>Współrzędne skrzynki zostały zmienione</b> na własną wartość "
|
||||
#~ "wprowadzoną przez użytkownika."
|
||||
|
||||
#~ msgid "User-supplied location of the %s geocache"
|
||||
#~ msgstr "Współrzędne skrzynki %s wprowadzone przez użytkownika"
|
||||
|
||||
#~ msgid "Recommending is allowed only for 'Found it' logtypes."
|
||||
#~ msgstr "Rekomendacje są dozwolone jedynie z wpisem \"Znaleziona\"."
|
||||
|
||||
|
@ -839,6 +839,9 @@ class OAuthServer {
|
||||
if( ! $timestamp )
|
||||
throw new OAuthMissingParameterException('oauth_timestamp');
|
||||
|
||||
// Cast to integer. See issue #314.
|
||||
$timestamp = $timestamp + 0;
|
||||
|
||||
// verify that timestamp is recentish
|
||||
$now = time();
|
||||
if (abs($now - $timestamp) > $this->timestamp_threshold) {
|
||||
|
@ -6,186 +6,187 @@ use Exception;
|
||||
|
||||
class OkapiServiceRunner
|
||||
{
|
||||
#
|
||||
# This the list of all available OKAPI methods. All methods on this list become
|
||||
# immediately public and all of them have to be documented. It is not possible
|
||||
# to create an invisible or undocumented OKAPI method. If you want to test your
|
||||
# methods, you should do it in your local development server. If you want to
|
||||
# create a private, "internal" method, you still have to document it properly
|
||||
# (you may describe it as "internal" and accessible to selected consumer keys only).
|
||||
#
|
||||
public static $all_names = array(
|
||||
# Valid format: ^services/[0-9a-z_/]*$ (it means you may use only alphanumeric
|
||||
# characters and the "_" sign in your method names).
|
||||
'services/apisrv/installation',
|
||||
'services/apisrv/installations',
|
||||
'services/apisrv/stats',
|
||||
'services/apiref/method',
|
||||
'services/apiref/method_index',
|
||||
'services/apiref/issue',
|
||||
'services/attrs/attribute_index',
|
||||
'services/attrs/attribute',
|
||||
'services/attrs/attributes',
|
||||
'services/oauth/request_token',
|
||||
'services/oauth/authorize',
|
||||
'services/oauth/access_token',
|
||||
'services/caches/search/all',
|
||||
'services/caches/search/bbox',
|
||||
'services/caches/search/nearest',
|
||||
'services/caches/search/by_urls',
|
||||
'services/caches/search/save',
|
||||
'services/caches/shortcuts/search_and_retrieve',
|
||||
'services/caches/geocache',
|
||||
'services/caches/geocaches',
|
||||
'services/caches/mark',
|
||||
'services/caches/formatters/gpx',
|
||||
'services/caches/formatters/garmin',
|
||||
'services/caches/map/tile',
|
||||
'services/logs/entries',
|
||||
'services/logs/entry',
|
||||
'services/logs/logs',
|
||||
'services/logs/userlogs',
|
||||
'services/logs/submit',
|
||||
'services/users/user',
|
||||
'services/users/users',
|
||||
'services/users/by_usernames',
|
||||
'services/users/by_username',
|
||||
'services/users/by_internal_id',
|
||||
'services/users/by_internal_ids',
|
||||
'services/replicate/changelog',
|
||||
'services/replicate/fulldump',
|
||||
'services/replicate/info',
|
||||
);
|
||||
#
|
||||
# This the list of all available OKAPI methods. All methods on this list become
|
||||
# immediately public and all of them have to be documented. It is not possible
|
||||
# to create an invisible or undocumented OKAPI method. If you want to test your
|
||||
# methods, you should do it in your local development server. If you want to
|
||||
# create a private, "internal" method, you still have to document it properly
|
||||
# (you may describe it as "internal" and accessible to selected consumer keys only).
|
||||
#
|
||||
public static $all_names = array(
|
||||
# Valid format: ^services/[0-9a-z_/]*$ (it means you may use only alphanumeric
|
||||
# characters and the "_" sign in your method names).
|
||||
'services/apisrv/installation',
|
||||
'services/apisrv/installations',
|
||||
'services/apisrv/stats',
|
||||
'services/apiref/method',
|
||||
'services/apiref/method_index',
|
||||
'services/apiref/issue',
|
||||
'services/attrs/attribute_index',
|
||||
'services/attrs/attribute',
|
||||
'services/attrs/attributes',
|
||||
'services/oauth/request_token',
|
||||
'services/oauth/authorize',
|
||||
'services/oauth/access_token',
|
||||
'services/caches/search/all',
|
||||
'services/caches/search/bbox',
|
||||
'services/caches/search/nearest',
|
||||
'services/caches/search/by_urls',
|
||||
'services/caches/search/save',
|
||||
'services/caches/shortcuts/search_and_retrieve',
|
||||
'services/caches/geocache',
|
||||
'services/caches/geocaches',
|
||||
'services/caches/mark',
|
||||
'services/caches/save_personal_notes',
|
||||
'services/caches/formatters/gpx',
|
||||
'services/caches/formatters/garmin',
|
||||
'services/caches/map/tile',
|
||||
'services/logs/entries',
|
||||
'services/logs/entry',
|
||||
'services/logs/logs',
|
||||
'services/logs/userlogs',
|
||||
'services/logs/submit',
|
||||
'services/users/user',
|
||||
'services/users/users',
|
||||
'services/users/by_usernames',
|
||||
'services/users/by_username',
|
||||
'services/users/by_internal_id',
|
||||
'services/users/by_internal_ids',
|
||||
'services/replicate/changelog',
|
||||
'services/replicate/fulldump',
|
||||
'services/replicate/info',
|
||||
);
|
||||
|
||||
/** Check if method exists. */
|
||||
public static function exists($service_name)
|
||||
{
|
||||
return in_array($service_name, self::$all_names);
|
||||
}
|
||||
/** Check if method exists. */
|
||||
public static function exists($service_name)
|
||||
{
|
||||
return in_array($service_name, self::$all_names);
|
||||
}
|
||||
|
||||
/** Get method options (is consumer required etc.). */
|
||||
public static function options($service_name)
|
||||
{
|
||||
if (!self::exists($service_name))
|
||||
throw new Exception();
|
||||
require_once($GLOBALS['rootpath']."okapi/$service_name.php");
|
||||
try
|
||||
{
|
||||
return call_user_func(array('\\okapi\\'.
|
||||
str_replace('/', '\\', $service_name).'\\WebService', 'options'));
|
||||
} catch (Exception $e)
|
||||
{
|
||||
throw new Exception("Make sure you've declared your WebService class ".
|
||||
"in an valid namespace (".'okapi\\'.str_replace('/', '\\', $service_name)."); ".
|
||||
$e->getMessage());
|
||||
}
|
||||
}
|
||||
/** Get method options (is consumer required etc.). */
|
||||
public static function options($service_name)
|
||||
{
|
||||
if (!self::exists($service_name))
|
||||
throw new Exception();
|
||||
require_once($GLOBALS['rootpath']."okapi/$service_name.php");
|
||||
try
|
||||
{
|
||||
return call_user_func(array('\\okapi\\'.
|
||||
str_replace('/', '\\', $service_name).'\\WebService', 'options'));
|
||||
} catch (Exception $e)
|
||||
{
|
||||
throw new Exception("Make sure you've declared your WebService class ".
|
||||
"in an valid namespace (".'okapi\\'.str_replace('/', '\\', $service_name)."); ".
|
||||
$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get method documentation file contents (stuff within the XML file).
|
||||
* If you're looking for a parsed representation, use services/apiref/method.
|
||||
*/
|
||||
public static function docs($service_name)
|
||||
{
|
||||
if (!self::exists($service_name))
|
||||
throw new Exception();
|
||||
try {
|
||||
return file_get_contents("$service_name.xml", true);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("Missing documentation file: $service_name.xml");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get method documentation file contents (stuff within the XML file).
|
||||
* If you're looking for a parsed representation, use services/apiref/method.
|
||||
*/
|
||||
public static function docs($service_name)
|
||||
{
|
||||
if (!self::exists($service_name))
|
||||
throw new Exception();
|
||||
try {
|
||||
return file_get_contents("$service_name.xml", true);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("Missing documentation file: $service_name.xml");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the method and return the result.
|
||||
*
|
||||
* OKAPI methods return OkapiHttpResponses, but some MAY also return
|
||||
* PHP objects (see OkapiRequest::construct_inside_request for details).
|
||||
*
|
||||
* If $request must be consistent with given method's options (must
|
||||
* include Consumer and Token, if they are required).
|
||||
*/
|
||||
public static function call($service_name, OkapiRequest $request)
|
||||
{
|
||||
Okapi::init_internals();
|
||||
/**
|
||||
* Execute the method and return the result.
|
||||
*
|
||||
* OKAPI methods return OkapiHttpResponses, but some MAY also return
|
||||
* PHP objects (see OkapiRequest::construct_inside_request for details).
|
||||
*
|
||||
* If $request must be consistent with given method's options (must
|
||||
* include Consumer and Token, if they are required).
|
||||
*/
|
||||
public static function call($service_name, OkapiRequest $request)
|
||||
{
|
||||
Okapi::init_internals();
|
||||
|
||||
if (!self::exists($service_name))
|
||||
throw new Exception("Method does not exist: '$service_name'");
|
||||
if (!self::exists($service_name))
|
||||
throw new Exception("Method does not exist: '$service_name'");
|
||||
|
||||
$options = self::options($service_name);
|
||||
if ($options['min_auth_level'] >= 2 && $request->consumer == null)
|
||||
{
|
||||
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
||||
"\$request->consumer MAY NOT be empty for Level 2 and Level 3 methods. Provide ".
|
||||
"a dummy Consumer if you have to.");
|
||||
}
|
||||
if ($options['min_auth_level'] >= 3 && $request->token == null)
|
||||
{
|
||||
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
||||
"\$request->token MAY NOT be empty for Level 3 methods.");
|
||||
}
|
||||
$options = self::options($service_name);
|
||||
if ($options['min_auth_level'] >= 2 && $request->consumer == null)
|
||||
{
|
||||
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
||||
"\$request->consumer MAY NOT be empty for Level 2 and Level 3 methods. Provide ".
|
||||
"a dummy Consumer if you have to.");
|
||||
}
|
||||
if ($options['min_auth_level'] >= 3 && $request->token == null)
|
||||
{
|
||||
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
||||
"\$request->token MAY NOT be empty for Level 3 methods.");
|
||||
}
|
||||
|
||||
$time_started = microtime(true);
|
||||
Okapi::gettext_domain_init();
|
||||
try
|
||||
{
|
||||
require_once($GLOBALS['rootpath']."okapi/$service_name.php");
|
||||
$response = call_user_func(array('\\okapi\\'.
|
||||
str_replace('/', '\\', $service_name).'\\WebService', 'call'), $request);
|
||||
Okapi::gettext_domain_restore();
|
||||
} catch (Exception $e) {
|
||||
Okapi::gettext_domain_restore();
|
||||
throw $e;
|
||||
}
|
||||
$runtime = microtime(true) - $time_started;
|
||||
$time_started = microtime(true);
|
||||
Okapi::gettext_domain_init();
|
||||
try
|
||||
{
|
||||
require_once($GLOBALS['rootpath']."okapi/$service_name.php");
|
||||
$response = call_user_func(array('\\okapi\\'.
|
||||
str_replace('/', '\\', $service_name).'\\WebService', 'call'), $request);
|
||||
Okapi::gettext_domain_restore();
|
||||
} catch (Exception $e) {
|
||||
Okapi::gettext_domain_restore();
|
||||
throw $e;
|
||||
}
|
||||
$runtime = microtime(true) - $time_started;
|
||||
|
||||
# Log the request to the stats table. Only valid requests (these which didn't end up
|
||||
# with an exception) are logged.
|
||||
self::save_stats($service_name, $request, $runtime);
|
||||
# Log the request to the stats table. Only valid requests (these which didn't end up
|
||||
# with an exception) are logged.
|
||||
self::save_stats($service_name, $request, $runtime);
|
||||
|
||||
return $response;
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* For internal use only. The stats table can be used to store any kind of
|
||||
* runtime-stats data, i.e. not only regarding services. This is a special
|
||||
* version of save_stats which saves runtime stats under the name of $extra_name.
|
||||
* Note, that $request can be null.
|
||||
*/
|
||||
public static function save_stats_extra($extra_name, $request, $runtime)
|
||||
{
|
||||
self::save_stats("extra/".$extra_name, $request, $runtime);
|
||||
}
|
||||
/**
|
||||
* For internal use only. The stats table can be used to store any kind of
|
||||
* runtime-stats data, i.e. not only regarding services. This is a special
|
||||
* version of save_stats which saves runtime stats under the name of $extra_name.
|
||||
* Note, that $request can be null.
|
||||
*/
|
||||
public static function save_stats_extra($extra_name, $request, $runtime)
|
||||
{
|
||||
self::save_stats("extra/".$extra_name, $request, $runtime);
|
||||
}
|
||||
|
||||
private static function save_stats($service_name, $request, $runtime)
|
||||
{
|
||||
# Getting rid of nulls. MySQL PRIMARY keys cannot contain nullable columns.
|
||||
# Temp table doesn't have primary key, but other stats tables (which are
|
||||
# dependant on stats table) - do.
|
||||
private static function save_stats($service_name, $request, $runtime)
|
||||
{
|
||||
# Getting rid of nulls. MySQL PRIMARY keys cannot contain nullable columns.
|
||||
# Temp table doesn't have primary key, but other stats tables (which are
|
||||
# dependant on stats table) - do.
|
||||
|
||||
if ($request !== null) {
|
||||
$consumer_key = ($request->consumer != null) ? $request->consumer->key : 'anonymous';
|
||||
$user_id = (($request->token != null) && ($request->token instanceof OkapiAccessToken)) ? $request->token->user_id : -1;
|
||||
if ($request->is_http_request() && ($service_name[0] == 's')) # 's' for "services/", we don't want "extra/" included
|
||||
$calltype = 'http';
|
||||
else
|
||||
$calltype = 'internal';
|
||||
} else {
|
||||
$consumer_key = 'internal';
|
||||
$user_id = -1;
|
||||
$calltype = 'internal';
|
||||
}
|
||||
if ($request !== null) {
|
||||
$consumer_key = ($request->consumer != null) ? $request->consumer->key : 'anonymous';
|
||||
$user_id = (($request->token != null) && ($request->token instanceof OkapiAccessToken)) ? $request->token->user_id : -1;
|
||||
if ($request->is_http_request() && ($service_name[0] == 's')) # 's' for "services/", we don't want "extra/" included
|
||||
$calltype = 'http';
|
||||
else
|
||||
$calltype = 'internal';
|
||||
} else {
|
||||
$consumer_key = 'internal';
|
||||
$user_id = -1;
|
||||
$calltype = 'internal';
|
||||
}
|
||||
|
||||
Db::execute("
|
||||
insert into okapi_stats_temp (`datetime`, consumer_key, user_id, service_name, calltype, runtime)
|
||||
values (
|
||||
now(),
|
||||
'".mysql_real_escape_string($consumer_key)."',
|
||||
'".mysql_real_escape_string($user_id)."',
|
||||
'".mysql_real_escape_string($service_name)."',
|
||||
'".mysql_real_escape_string($calltype)."',
|
||||
'".mysql_real_escape_string($runtime)."'
|
||||
);
|
||||
");
|
||||
}
|
||||
Db::execute("
|
||||
insert into okapi_stats_temp (`datetime`, consumer_key, user_id, service_name, calltype, runtime)
|
||||
values (
|
||||
now(),
|
||||
'".mysql_real_escape_string($consumer_key)."',
|
||||
'".mysql_real_escape_string($user_id)."',
|
||||
'".mysql_real_escape_string($service_name)."',
|
||||
'".mysql_real_escape_string($calltype)."',
|
||||
'".mysql_real_escape_string($runtime)."'
|
||||
);
|
||||
");
|
||||
}
|
||||
}
|
@ -15,32 +15,32 @@ use okapi\Cache;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$issue_id = $request->get_parameter('issue_id');
|
||||
if (!$issue_id)
|
||||
throw new ParamMissing('issue_id');
|
||||
if ((!preg_match("/^[0-9]+$/", $issue_id)) || (strlen($issue_id) > 6))
|
||||
throw new InvalidParam('issue_id');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$issue_id = $request->get_parameter('issue_id');
|
||||
if (!$issue_id)
|
||||
throw new ParamMissing('issue_id');
|
||||
if ((!preg_match("/^[0-9]+$/", $issue_id)) || (strlen($issue_id) > 6))
|
||||
throw new InvalidParam('issue_id');
|
||||
|
||||
# In October 2013, Google Code feed at:
|
||||
# http://code.google.com/feeds/issues/p/opencaching-api/issues/$issue_id/comments/full
|
||||
# stopped working. We are forced to respond with a simple placeholder.
|
||||
|
||||
$result = array(
|
||||
'id' => $issue_id + 0,
|
||||
'last_updated' => null,
|
||||
'title' => null,
|
||||
'url' => "https://code.google.com/p/opencaching-api/issues/detail?id=".$issue_id,
|
||||
'comment_count' => null
|
||||
);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
# In October 2013, Google Code feed at:
|
||||
# http://code.google.com/feeds/issues/p/opencaching-api/issues/$issue_id/comments/full
|
||||
# stopped working. We are forced to respond with a simple placeholder.
|
||||
|
||||
$result = array(
|
||||
'id' => $issue_id + 0,
|
||||
'last_updated' => null,
|
||||
'title' => null,
|
||||
'url' => "https://code.google.com/p/opencaching-api/issues/detail?id=".$issue_id,
|
||||
'comment_count' => null
|
||||
);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,33 @@
|
||||
<xml>
|
||||
<brief>Retrieve information on given issue</brief>
|
||||
<issue-id>11</issue-id>
|
||||
<desc>
|
||||
<p><b>Important:</b> This method stopped working properly in October 2013.
|
||||
Now, it returns a simple placeholder.
|
||||
<a href='https://code.google.com/p/opencaching-api/issues/detail?id=288'>Read more</a>.</p>
|
||||
|
||||
<p>OKAPI is trying to be as <b>integrated</b> with its
|
||||
<a href='http://code.google.com/p/opencaching-api/'>Main Project Page</a> as it can.
|
||||
This method retrieves basic information on a given issue from our project
|
||||
<a href='http://code.google.com/p/opencaching-api/issues/list'>Issue Tracker</a>.
|
||||
In future, it <b>might</b> also return some of the latest comments (we're not yet
|
||||
sure if we want them displayed on our documentation pages).</p>
|
||||
</desc>
|
||||
<req name='issue_id'>
|
||||
ID of an Issue.
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>id</b> - number of the issue created for this method,</li>
|
||||
<li><b>last_updated</b> - date and time (ISO 8601) when the issue was last updated
|
||||
<b>or null</b> if unknown,</li>
|
||||
<li><b>title</b> - issue title <b>or null</b> if unknown,</li>
|
||||
<li><b>url</b> - URL of the issue page,</li>
|
||||
<li><b>comment_count</b> - total number of submitted comments <b>or null</b> if unknown.</li>
|
||||
</ul>
|
||||
<p>Note, that this will respond with HTTP 400 if we fail to retrieve data from
|
||||
the Google Code site.</p>
|
||||
</returns>
|
||||
<brief>Retrieve information on given issue</brief>
|
||||
<issue-id>11</issue-id>
|
||||
<desc>
|
||||
<p><b>Important:</b> This method stopped working properly in October 2013.
|
||||
Now, it returns a simple placeholder.
|
||||
<a href='https://code.google.com/p/opencaching-api/issues/detail?id=288'>Read more</a>.</p>
|
||||
|
||||
<p>OKAPI is trying to be as <b>integrated</b> with its
|
||||
<a href='http://code.google.com/p/opencaching-api/'>Main Project Page</a> as it can.
|
||||
This method retrieves basic information on a given issue from our project
|
||||
<a href='http://code.google.com/p/opencaching-api/issues/list'>Issue Tracker</a>.
|
||||
In future, it <b>might</b> also return some of the latest comments (we're not yet
|
||||
sure if we want them displayed on our documentation pages).</p>
|
||||
</desc>
|
||||
<req name='issue_id'>
|
||||
ID of an Issue.
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>id</b> - number of the issue created for this method,</li>
|
||||
<li><b>last_updated</b> - date and time (ISO 8601) when the issue was last updated
|
||||
<b>or null</b> if unknown,</li>
|
||||
<li><b>title</b> - issue title <b>or null</b> if unknown,</li>
|
||||
<li><b>url</b> - URL of the issue page,</li>
|
||||
<li><b>comment_count</b> - total number of submitted comments <b>or null</b> if unknown.</li>
|
||||
</ul>
|
||||
<p>Note, that this will respond with HTTP 400 if we fail to retrieve data from
|
||||
the Google Code site.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -14,158 +14,216 @@ use okapi\OkapiInternalConsumer;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
private static function arg_desc($arg_node)
|
||||
{
|
||||
$attrs = $arg_node->attributes();
|
||||
return array(
|
||||
'name' => (string)$attrs['name'],
|
||||
'is_required' => $arg_node->getName() == 'req',
|
||||
'is_deprecated' => (isset($attrs['class']) && (strpos($attrs['class'], 'deprecated') !== false)),
|
||||
'class' => 'public',
|
||||
'description' =>
|
||||
(isset($attrs['default']) ? ("<p>Default value: <b>".$attrs['default']."</b></p>") : "").
|
||||
self::get_inner_xml($arg_node),
|
||||
private static function arg_desc($arg_node)
|
||||
{
|
||||
$attrs = $arg_node->attributes();
|
||||
return array(
|
||||
'name' => (string)$attrs['name'],
|
||||
'is_required' => $arg_node->getName() == 'req',
|
||||
'is_deprecated' => (isset($attrs['class']) && (strpos($attrs['class'], 'deprecated') !== false)),
|
||||
'class' => 'public',
|
||||
'description' =>
|
||||
(isset($attrs['default']) ? ("<p>Default value: <b>".$attrs['default']."</b></p>") : "").
|
||||
self::get_inner_xml($arg_node),
|
||||
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static function get_inner_xml($node)
|
||||
{
|
||||
/* Fetch as <some-node>content</some-node>, extract content. */
|
||||
private static function get_inner_xml($node)
|
||||
{
|
||||
/* Fetch as <some-node>content</some-node>, extract content. */
|
||||
|
||||
$s = $node->asXML();
|
||||
$start = strpos($s, ">") + 1;
|
||||
$length = strlen($s) - $start - (3 + strlen($node->getName()));
|
||||
$s = substr($s, $start, $length);
|
||||
$s = $node->asXML();
|
||||
$start = strpos($s, ">") + 1;
|
||||
$length = strlen($s) - $start - (3 + strlen($node->getName()));
|
||||
$s = substr($s, $start, $length);
|
||||
|
||||
/* Find and replace %okapi:plugins%. */
|
||||
/* Find and replace %okapi:plugins%. */
|
||||
|
||||
$s = preg_replace_callback("~%OKAPI:([a-z:]+)%~", array("self", "plugin_callback"), $s);
|
||||
$s = preg_replace_callback('~%OKAPI:([a-z:/_#]+)%~', array("self", "plugin_callback"), $s);
|
||||
|
||||
return $s;
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
public static function plugin_callback($matches)
|
||||
{
|
||||
$input = $matches[1];
|
||||
$arr = explode(":", $input);
|
||||
$plugin_name = $arr[0];
|
||||
/**
|
||||
* You can use the following syntax:
|
||||
*
|
||||
* <a href="%OKAPI:docurl:fragment%">any text</a> - to reference fragment of introducing
|
||||
* documentation
|
||||
*
|
||||
* <a href="%OKAPI:methodref:methodname%">any text</a> - to reference any other method
|
||||
*
|
||||
* <a href="%OKAPI:methodref:methodname#html_anchor%">any text</a> - to reference
|
||||
* any HTML anchor in other method
|
||||
*
|
||||
* <a href="%OKAPI:methodref:#html_anchor%">any text</a> - to reference any HTML
|
||||
* anchor within current document
|
||||
*
|
||||
* <a href="%OKAPI:methodargref:methodname#argument_name%">any text</a> - to
|
||||
* reference argument of another method
|
||||
*
|
||||
* <a href="%OKAPI:methodargref:#argument_name%">any text</a> - to reference
|
||||
* argument within current method
|
||||
*
|
||||
* <a href="%OKAPI:methodretref:methodname#returned_key%">any text</a> - to
|
||||
* reference returned value of another method
|
||||
*
|
||||
* <a href="%OKAPI:methodretref:#returned_key%">any text</a> - to reference
|
||||
* returned value within current method
|
||||
*
|
||||
* NOTE!
|
||||
*
|
||||
* Since returned JSON dictionaries are not standardized (they are simply plain
|
||||
* HTML in the docs), to reference returned values you must manually create an
|
||||
* anchor prefixed with ret_, i.e. (HTML snippet): <li
|
||||
* id="ret_alt_wpts"><p><b>alt_wpts</b> - list of alternate/additional
|
||||
* waypoints</...> and access it with (HTML snippet): <a
|
||||
* href="%OKAPI:methodretref:#alt_wpts%">any text</a>.
|
||||
*/
|
||||
public static function plugin_callback($matches)
|
||||
{
|
||||
$input = $matches[1];
|
||||
$arr = explode(":", $input);
|
||||
$plugin_name = $arr[0];
|
||||
|
||||
switch ($plugin_name) {
|
||||
case 'docurl':
|
||||
$fragment = $arr[1];
|
||||
return Settings::get('SITE_URL')."okapi/introduction.html#".$fragment;
|
||||
default:
|
||||
throw new Exception("Unknown plugin: ".$input);
|
||||
}
|
||||
}
|
||||
switch ($plugin_name) {
|
||||
case 'docurl':
|
||||
$fragment = $arr[1];
|
||||
return Settings::get('SITE_URL')."okapi/introduction.html#".$fragment;
|
||||
case 'methodref':
|
||||
case 'methodargref':
|
||||
case 'methodretref':
|
||||
$elements = explode('#', $arr[1]);
|
||||
$result = '';
|
||||
if ($elements[0] != '')
|
||||
{
|
||||
$result .= Settings::get('SITE_URL')."okapi/".$elements[0].'.html';
|
||||
}
|
||||
if (count($elements) > 1)
|
||||
{
|
||||
$result .= '#';
|
||||
switch ($plugin_name) {
|
||||
case 'methodargref':
|
||||
$result .= 'arg_';
|
||||
break;
|
||||
case 'methodretref':
|
||||
$result .= 'ret_';
|
||||
break;
|
||||
}
|
||||
$result .= $elements[1];
|
||||
}
|
||||
return $result;
|
||||
default:
|
||||
throw new Exception("Unknown plugin: ".$input);
|
||||
}
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$methodname = $request->get_parameter('name');
|
||||
if (!$methodname)
|
||||
throw new ParamMissing('name');
|
||||
if (!preg_match("#^services/[0-9a-z_/]*$#", $methodname))
|
||||
throw new InvalidParam('name');
|
||||
if (!OkapiServiceRunner::exists($methodname))
|
||||
throw new InvalidParam('name', "Method does not exist: '$methodname'.");
|
||||
$options = OkapiServiceRunner::options($methodname);
|
||||
if (!isset($options['min_auth_level']))
|
||||
throw new Exception("Method $methodname is missing a required 'min_auth_level' option!");
|
||||
$docs = simplexml_load_string(OkapiServiceRunner::docs($methodname));
|
||||
$exploded = explode("/", $methodname);
|
||||
$result = array(
|
||||
'name' => $methodname,
|
||||
'short_name' => end($exploded),
|
||||
'ref_url' => Settings::get('SITE_URL')."okapi/$methodname.html",
|
||||
'auth_options' => array(
|
||||
'min_auth_level' => $options['min_auth_level'],
|
||||
'oauth_consumer' => $options['min_auth_level'] >= 2,
|
||||
'oauth_token' => $options['min_auth_level'] >= 3,
|
||||
)
|
||||
);
|
||||
if (!$docs->brief)
|
||||
throw new Exception("Missing <brief> element in the $methodname.xml file.");
|
||||
if ($docs->brief != self::get_inner_xml($docs->brief))
|
||||
throw new Exception("The <brief> element may not contain HTML markup ($methodname.xml).");
|
||||
if (strlen($docs->brief) > 80)
|
||||
throw new Exception("The <brief> description may not be longer than 80 characters ($methodname.xml).");
|
||||
if (strpos($docs->brief, "\n") !== false)
|
||||
throw new Exception("The <brief> element may not contain new-lines ($methodname.xml).");
|
||||
if (substr(trim($docs->brief), -1) == '.')
|
||||
throw new Exception("The <brief> element should not end with a dot ($methodname.xml).");
|
||||
$result['brief_description'] = self::get_inner_xml($docs->brief);
|
||||
if ($docs->{'issue-id'})
|
||||
$result['issue_id'] = (string)$docs->{'issue-id'};
|
||||
else
|
||||
$result['issue_id'] = null;
|
||||
if (!$docs->desc)
|
||||
throw new Exception("Missing <desc> element in the $methodname.xml file.");
|
||||
$result['description'] = self::get_inner_xml($docs->desc);
|
||||
$result['arguments'] = array();
|
||||
foreach ($docs->req as $arg) { $result['arguments'][] = self::arg_desc($arg); }
|
||||
foreach ($docs->opt as $arg) { $result['arguments'][] = self::arg_desc($arg); }
|
||||
foreach ($docs->{'import-params'} as $import_desc)
|
||||
{
|
||||
$attrs = $import_desc->attributes();
|
||||
$referenced_methodname = $attrs['method'];
|
||||
$referenced_method_info = OkapiServiceRunner::call('services/apiref/method',
|
||||
new OkapiInternalRequest(new OkapiInternalConsumer(), null, array('name' => $referenced_methodname)));
|
||||
$include_list = isset($attrs['params']) ? explode("|", $attrs['params']) : null;
|
||||
$exclude_list = isset($attrs['except']) ? explode("|", $attrs['except']) : array();
|
||||
foreach ($referenced_method_info['arguments'] as $arg)
|
||||
{
|
||||
if ($arg['class'] == 'common-formatting')
|
||||
continue;
|
||||
if (($include_list === null) && (count($exclude_list) == 0))
|
||||
{
|
||||
$arg['description'] = "<i>Inherited from <a href='".$referenced_method_info['ref_url'].
|
||||
"'>".$referenced_method_info['name']."</a> method.</i>";
|
||||
}
|
||||
elseif (
|
||||
(($include_list === null) || in_array($arg['name'], $include_list))
|
||||
&& (!in_array($arg['name'], $exclude_list))
|
||||
) {
|
||||
$arg['description'] = "<i>Same as in the <a href='".$referenced_method_info['ref_url'].
|
||||
"'>".$referenced_method_info['name']."</a> method.</i>";
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
$arg['class'] = 'inherited';
|
||||
$result['arguments'][] = $arg;
|
||||
}
|
||||
}
|
||||
if ($docs->{'common-format-params'})
|
||||
{
|
||||
$result['arguments'][] = array(
|
||||
'name' => 'format',
|
||||
'is_required' => false,
|
||||
'is_deprecated' => false,
|
||||
'class' => 'common-formatting',
|
||||
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
|
||||
);
|
||||
$result['arguments'][] = array(
|
||||
'name' => 'callback',
|
||||
'is_required' => false,
|
||||
'is_deprecated' => false,
|
||||
'class' => 'common-formatting',
|
||||
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
|
||||
);
|
||||
}
|
||||
foreach ($result['arguments'] as &$arg_ref)
|
||||
if ($arg_ref['is_deprecated'])
|
||||
$arg_ref['class'] .= " deprecated";
|
||||
if (!$docs->returns)
|
||||
throw new Exception("Missing <returns> element in the $methodname.xml file. ".
|
||||
"If your method does not return anything, you should document in nonetheless.");
|
||||
$result['returns'] = self::get_inner_xml($docs->returns);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$methodname = $request->get_parameter('name');
|
||||
if (!$methodname)
|
||||
throw new ParamMissing('name');
|
||||
if (!preg_match("#^services/[0-9a-z_/]*$#", $methodname))
|
||||
throw new InvalidParam('name');
|
||||
if (!OkapiServiceRunner::exists($methodname))
|
||||
throw new InvalidParam('name', "Method does not exist: '$methodname'.");
|
||||
$options = OkapiServiceRunner::options($methodname);
|
||||
if (!isset($options['min_auth_level']))
|
||||
throw new Exception("Method $methodname is missing a required 'min_auth_level' option!");
|
||||
$docs = simplexml_load_string(OkapiServiceRunner::docs($methodname));
|
||||
$exploded = explode("/", $methodname);
|
||||
$result = array(
|
||||
'name' => $methodname,
|
||||
'short_name' => end($exploded),
|
||||
'ref_url' => Settings::get('SITE_URL')."okapi/$methodname.html",
|
||||
'auth_options' => array(
|
||||
'min_auth_level' => $options['min_auth_level'],
|
||||
'oauth_consumer' => $options['min_auth_level'] >= 2,
|
||||
'oauth_token' => $options['min_auth_level'] >= 3,
|
||||
)
|
||||
);
|
||||
if (!$docs->brief)
|
||||
throw new Exception("Missing <brief> element in the $methodname.xml file.");
|
||||
if ($docs->brief != self::get_inner_xml($docs->brief))
|
||||
throw new Exception("The <brief> element may not contain HTML markup ($methodname.xml).");
|
||||
if (strlen($docs->brief) > 80)
|
||||
throw new Exception("The <brief> description may not be longer than 80 characters ($methodname.xml).");
|
||||
if (strpos($docs->brief, "\n") !== false)
|
||||
throw new Exception("The <brief> element may not contain new-lines ($methodname.xml).");
|
||||
if (substr(trim($docs->brief), -1) == '.')
|
||||
throw new Exception("The <brief> element should not end with a dot ($methodname.xml).");
|
||||
$result['brief_description'] = self::get_inner_xml($docs->brief);
|
||||
if ($docs->{'issue-id'})
|
||||
$result['issue_id'] = (string)$docs->{'issue-id'};
|
||||
else
|
||||
$result['issue_id'] = null;
|
||||
if (!$docs->desc)
|
||||
throw new Exception("Missing <desc> element in the $methodname.xml file.");
|
||||
$result['description'] = self::get_inner_xml($docs->desc);
|
||||
$result['arguments'] = array();
|
||||
foreach ($docs->req as $arg) { $result['arguments'][] = self::arg_desc($arg); }
|
||||
foreach ($docs->opt as $arg) { $result['arguments'][] = self::arg_desc($arg); }
|
||||
foreach ($docs->{'import-params'} as $import_desc)
|
||||
{
|
||||
$attrs = $import_desc->attributes();
|
||||
$referenced_methodname = $attrs['method'];
|
||||
$referenced_method_info = OkapiServiceRunner::call('services/apiref/method',
|
||||
new OkapiInternalRequest(new OkapiInternalConsumer(), null, array('name' => $referenced_methodname)));
|
||||
$include_list = isset($attrs['params']) ? explode("|", $attrs['params']) : null;
|
||||
$exclude_list = isset($attrs['except']) ? explode("|", $attrs['except']) : array();
|
||||
foreach ($referenced_method_info['arguments'] as $arg)
|
||||
{
|
||||
if ($arg['class'] == 'common-formatting')
|
||||
continue;
|
||||
if (($include_list === null) && (count($exclude_list) == 0))
|
||||
{
|
||||
$arg['description'] = "<i>Inherited from <a href='".$referenced_method_info['ref_url'].
|
||||
"'>".$referenced_method_info['name']."</a> method.</i>";
|
||||
}
|
||||
elseif (
|
||||
(($include_list === null) || in_array($arg['name'], $include_list))
|
||||
&& (!in_array($arg['name'], $exclude_list))
|
||||
) {
|
||||
$arg['description'] = "<i>Same as in the <a href='".$referenced_method_info['ref_url'].
|
||||
"'>".$referenced_method_info['name']."</a> method.</i>";
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
$arg['class'] = 'inherited';
|
||||
$result['arguments'][] = $arg;
|
||||
}
|
||||
}
|
||||
if ($docs->{'common-format-params'})
|
||||
{
|
||||
$result['arguments'][] = array(
|
||||
'name' => 'format',
|
||||
'is_required' => false,
|
||||
'is_deprecated' => false,
|
||||
'class' => 'common-formatting',
|
||||
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
|
||||
);
|
||||
$result['arguments'][] = array(
|
||||
'name' => 'callback',
|
||||
'is_required' => false,
|
||||
'is_deprecated' => false,
|
||||
'class' => 'common-formatting',
|
||||
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
|
||||
);
|
||||
}
|
||||
foreach ($result['arguments'] as &$arg_ref)
|
||||
if ($arg_ref['is_deprecated'])
|
||||
$arg_ref['class'] .= " deprecated";
|
||||
if (!$docs->returns)
|
||||
throw new Exception("Missing <returns> element in the $methodname.xml file. ".
|
||||
"If your method does not return anything, you should document in nonetheless.");
|
||||
$result['returns'] = self::get_inner_xml($docs->returns);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +1,55 @@
|
||||
<xml>
|
||||
<brief>Get information on a given OKAPI service method</brief>
|
||||
<issue-id>13</issue-id>
|
||||
<desc>
|
||||
<p>This method allows you to <b>access API documentation</b> (the same which you
|
||||
are reading just now). Given a method name, it returns a complete method description.</p>
|
||||
</desc>
|
||||
<req name='name'>
|
||||
Name of a method (begins with "services/").
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>name</b> - name of the method,</li>
|
||||
<li><b>short_name</b> - name without a path,</li>
|
||||
<li><b>issue_id</b> - ID of the "general discussion" issue (in our project's
|
||||
homepage Issue Tracker) associated with this method <b>or null</b> if this
|
||||
method has associated issue,</li>
|
||||
<li><b>description</b> - HTML-formatted description of what the method does,</li>
|
||||
<li><b>brief_description</b> - brief (max 80 characters), single-line,
|
||||
plain-text description of what the method does,</li>
|
||||
<li><b>ref_url</b> - URL of the documentation page with method description,</li>
|
||||
<li>
|
||||
<b>auth_options</b> - a dictionary which describes authentication
|
||||
requirements for this method, it has a following structure:
|
||||
<ul>
|
||||
<li><b>min_auth_level</b> - integer, in range from 0 to 3,
|
||||
see Introduction page.</li>
|
||||
<li><b>oauth_consumer</b> - true, if requests are required to be signed
|
||||
with OAuth Consumer Key (min_auth_level >= 2),</li>
|
||||
<li><b>oauth_token</b> - true, if requests are required to include an
|
||||
OAuth Token (min_auth_level == 3).</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>arguments</b> - list of dictionaries, describes method
|
||||
arguments. Each dictionary has a following structure:
|
||||
<ul>
|
||||
<li><b>name</b> - name of an argument,</li>
|
||||
<li><b>is_required</b> - boolean, true if the argument is required,</li>
|
||||
<li><b>is_deprecated</b> - boolean, true if the argument is deprecated,</li>
|
||||
<li><b>description</b> - HTML-formatted description of an argument.</li>
|
||||
<li>
|
||||
<p><b>class</b> - space separated list of the following values: <i>public</i>,
|
||||
<i>inherited</i>, <i>common-formatting</i> and <i>deprecated</i>
|
||||
(other values might be introduced in future).</p>
|
||||
<p>Currently these values do not mean anything specific. They are
|
||||
used for different coloring/styling in the documentation pages.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>returns</b> - HTML-formatted description method's return value.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Get information on a given OKAPI service method</brief>
|
||||
<issue-id>13</issue-id>
|
||||
<desc>
|
||||
<p>This method allows you to <b>access API documentation</b> (the same which you
|
||||
are reading just now). Given a method name, it returns a complete method description.</p>
|
||||
</desc>
|
||||
<req name='name'>
|
||||
Name of a method (begins with "services/").
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>name</b> - name of the method,</li>
|
||||
<li><b>short_name</b> - name without a path,</li>
|
||||
<li><b>issue_id</b> - ID of the "general discussion" issue (in our project's
|
||||
homepage Issue Tracker) associated with this method <b>or null</b> if this
|
||||
method has associated issue,</li>
|
||||
<li><b>description</b> - HTML-formatted description of what the method does,</li>
|
||||
<li><b>brief_description</b> - brief (max 80 characters), single-line,
|
||||
plain-text description of what the method does,</li>
|
||||
<li><b>ref_url</b> - URL of the documentation page with method description,</li>
|
||||
<li>
|
||||
<b>auth_options</b> - a dictionary which describes authentication
|
||||
requirements for this method, it has a following structure:
|
||||
<ul>
|
||||
<li><b>min_auth_level</b> - integer, in range from 0 to 3,
|
||||
see Introduction page.</li>
|
||||
<li><b>oauth_consumer</b> - true, if requests are required to be signed
|
||||
with OAuth Consumer Key (min_auth_level >= 2),</li>
|
||||
<li><b>oauth_token</b> - true, if requests are required to include an
|
||||
OAuth Token (min_auth_level == 3).</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>arguments</b> - list of dictionaries, describes method
|
||||
arguments. Each dictionary has a following structure:
|
||||
<ul>
|
||||
<li><b>name</b> - name of an argument,</li>
|
||||
<li><b>is_required</b> - boolean, true if the argument is required,</li>
|
||||
<li><b>is_deprecated</b> - boolean, true if the argument is deprecated,</li>
|
||||
<li><b>description</b> - HTML-formatted description of an argument.</li>
|
||||
<li>
|
||||
<p><b>class</b> - space separated list of the following values: <i>public</i>,
|
||||
<i>inherited</i>, <i>common-formatting</i> and <i>deprecated</i>
|
||||
(other values might be introduced in future).</p>
|
||||
<p>Currently these values do not mean anything specific. They are
|
||||
used for different coloring/styling in the documentation pages.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>returns</b> - HTML-formatted description method's return value.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -15,33 +15,33 @@ use okapi\OkapiInternalRequest;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$methodnames = OkapiServiceRunner::$all_names;
|
||||
sort($methodnames);
|
||||
$cache_key = "api_ref/method_index#".md5(implode("#", $methodnames));
|
||||
$results = Cache::get($cache_key);
|
||||
if ($results == null)
|
||||
{
|
||||
$results = array();
|
||||
foreach ($methodnames as $methodname)
|
||||
{
|
||||
$info = OkapiServiceRunner::call('services/apiref/method', new OkapiInternalRequest(
|
||||
new OkapiInternalConsumer(), null, array('name' => $methodname)));
|
||||
$results[] = array(
|
||||
'name' => $info['name'],
|
||||
'brief_description' => $info['brief_description'],
|
||||
);
|
||||
}
|
||||
Cache::set($cache_key, $results, 3600);
|
||||
}
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$methodnames = OkapiServiceRunner::$all_names;
|
||||
sort($methodnames);
|
||||
$cache_key = "api_ref/method_index#".md5(implode("#", $methodnames));
|
||||
$results = Cache::get($cache_key);
|
||||
if ($results == null)
|
||||
{
|
||||
$results = array();
|
||||
foreach ($methodnames as $methodname)
|
||||
{
|
||||
$info = OkapiServiceRunner::call('services/apiref/method', new OkapiInternalRequest(
|
||||
new OkapiInternalConsumer(), null, array('name' => $methodname)));
|
||||
$results[] = array(
|
||||
'name' => $info['name'],
|
||||
'brief_description' => $info['brief_description'],
|
||||
);
|
||||
}
|
||||
Cache::set($cache_key, $results, 3600);
|
||||
}
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
<xml>
|
||||
<brief>Get a list of OKAPI methods with brief descriptions</brief>
|
||||
<issue-id>12</issue-id>
|
||||
<desc>
|
||||
<p>Get a list of OKAPI methods with brief descriptions.</p>
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
A list of dictionaries, each of which contains one API
|
||||
method description in the following format:
|
||||
<ul>
|
||||
<li><b>name</b> - name of a method,</li>
|
||||
<li><b>brief_description</b> - brief (max 80 characters), single-line,
|
||||
plain-text description of what the method does.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Get a list of OKAPI methods with brief descriptions</brief>
|
||||
<issue-id>12</issue-id>
|
||||
<desc>
|
||||
<p>Get a list of OKAPI methods with brief descriptions.</p>
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
A list of dictionaries, each of which contains one API
|
||||
method description in the following format:
|
||||
<ul>
|
||||
<li><b>name</b> - name of a method,</li>
|
||||
<li><b>brief_description</b> - brief (max 80 characters), single-line,
|
||||
plain-text description of what the method does.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -13,20 +13,20 @@ use okapi\OkapiInternalRequest;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$result = array();
|
||||
$result['site_url'] = Settings::get('SITE_URL');
|
||||
$result['okapi_base_url'] = $result['site_url']."okapi/";
|
||||
$result['site_name'] = Okapi::get_normalized_site_name();
|
||||
$result['okapi_revision'] = Okapi::$revision;
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$result = array();
|
||||
$result['site_url'] = Settings::get('SITE_URL');
|
||||
$result['okapi_base_url'] = $result['site_url']."okapi/";
|
||||
$result['site_name'] = Okapi::get_normalized_site_name();
|
||||
$result['okapi_revision'] = Okapi::$revision;
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
<xml>
|
||||
<brief>Get information on this OKAPI installation</brief>
|
||||
<issue-id>14</issue-id>
|
||||
<desc>
|
||||
Retrieve some basic information about this OKAPI installation.
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>site_url</b> - URL of the Opencaching site which is running
|
||||
the OKAPI installation (usually this looks like
|
||||
"http://www.opencaching.<i>xx</i>/", where <b>xx</b> is a top
|
||||
level domain of a country).
|
||||
</li>
|
||||
<li>
|
||||
<b>okapi_base_url</b> - URL of the OKAPI installation (usually this is
|
||||
<b>site_url</b> with "okapi/" appended, but you should not assume
|
||||
that); this value is to be used as a prefix when constructing service
|
||||
method URLs,
|
||||
</li>
|
||||
<li>
|
||||
<b>site_name</b> - international name of the Opencaching site,
|
||||
</li>
|
||||
<li><b>okapi_revision</b> - integer, an SVN revision of the OKAPI project
|
||||
installed on this Opencaching site, <b>or null</b>, when could not
|
||||
determine revision number.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Get information on this OKAPI installation</brief>
|
||||
<issue-id>14</issue-id>
|
||||
<desc>
|
||||
Retrieve some basic information about this OKAPI installation.
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>site_url</b> - URL of the Opencaching site which is running
|
||||
the OKAPI installation (usually this looks like
|
||||
"http://www.opencaching.<i>xx</i>/", where <b>xx</b> is a top
|
||||
level domain of a country).
|
||||
</li>
|
||||
<li>
|
||||
<b>okapi_base_url</b> - URL of the OKAPI installation (usually this is
|
||||
<b>site_url</b> with "okapi/" appended, but you should not assume
|
||||
that); this value is to be used as a prefix when constructing service
|
||||
method URLs,
|
||||
</li>
|
||||
<li>
|
||||
<b>site_name</b> - international name of the Opencaching site,
|
||||
</li>
|
||||
<li><b>okapi_revision</b> - integer, an SVN revision of the OKAPI project
|
||||
installed on this Opencaching site, <b>or null</b>, when could not
|
||||
determine revision number.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -15,104 +15,104 @@ use okapi\OkapiInternalRequest;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# The list of installations is periodically refreshed by contacting OKAPI
|
||||
# repository. This method usually displays the cached version of it.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# The list of installations is periodically refreshed by contacting OKAPI
|
||||
# repository. This method usually displays the cached version of it.
|
||||
|
||||
$cachekey = 'apisrv/installations';
|
||||
$backupkey = 'apisrv/installations-backup';
|
||||
$results = Cache::get($cachekey);
|
||||
if (!$results)
|
||||
{
|
||||
# Download the current list of OKAPI servers.
|
||||
$cachekey = 'apisrv/installations';
|
||||
$backupkey = 'apisrv/installations-backup';
|
||||
$results = Cache::get($cachekey);
|
||||
if (!$results)
|
||||
{
|
||||
# Download the current list of OKAPI servers.
|
||||
|
||||
try
|
||||
{
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'timeout' => 5.0
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$xml = file_get_contents("http://opencaching-api.googlecode.com/svn/trunk/etc/installations.xml",
|
||||
false, $context);
|
||||
}
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
# Google failed on us. Try to respond with a backup list.
|
||||
try
|
||||
{
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'timeout' => 5.0
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$xml = file_get_contents("http://opencaching-api.googlecode.com/svn/trunk/etc/installations.xml",
|
||||
false, $context);
|
||||
}
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
# Google failed on us. Try to respond with a backup list.
|
||||
|
||||
$results = Cache::get($backupkey);
|
||||
if ($results)
|
||||
{
|
||||
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
$results = Cache::get($backupkey);
|
||||
if ($results)
|
||||
{
|
||||
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
|
||||
# Backup has expired (or have never been cached). If we're on a development
|
||||
# server then probably it's okay. In production this SHOULD NOT happen.
|
||||
# Backup has expired (or have never been cached). If we're on a development
|
||||
# server then probably it's okay. In production this SHOULD NOT happen.
|
||||
|
||||
$results = array(
|
||||
array(
|
||||
'site_url' => Settings::get('SITE_URL'),
|
||||
'site_name' => "Unable to retrieve!",
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
)
|
||||
);
|
||||
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
$results = array(
|
||||
array(
|
||||
'site_url' => Settings::get('SITE_URL'),
|
||||
'site_name' => "Unable to retrieve!",
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
)
|
||||
);
|
||||
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
|
||||
$doc = simplexml_load_string($xml);
|
||||
$results = array();
|
||||
$i_was_included = false;
|
||||
foreach ($doc->installation as $inst)
|
||||
{
|
||||
$site_url = (string)$inst[0]['site_url'];
|
||||
if ($inst[0]['okapi_base_url'])
|
||||
$okapi_base_url = (string)$inst[0]['okapi_base_url'];
|
||||
else
|
||||
$okapi_base_url = $site_url."okapi/";
|
||||
if ($inst[0]['site_name'])
|
||||
$site_name = (string)$inst[0]['site_name'];
|
||||
else
|
||||
$site_name = Okapi::get_normalized_site_name($site_url);
|
||||
$results[] = array(
|
||||
'site_url' => $site_url,
|
||||
'site_name' => $site_name,
|
||||
'okapi_base_url' => $okapi_base_url,
|
||||
);
|
||||
if ($site_url == Settings::get('SITE_URL'))
|
||||
$i_was_included = true;
|
||||
}
|
||||
$doc = simplexml_load_string($xml);
|
||||
$results = array();
|
||||
$i_was_included = false;
|
||||
foreach ($doc->installation as $inst)
|
||||
{
|
||||
$site_url = (string)$inst[0]['site_url'];
|
||||
if ($inst[0]['okapi_base_url'])
|
||||
$okapi_base_url = (string)$inst[0]['okapi_base_url'];
|
||||
else
|
||||
$okapi_base_url = $site_url."okapi/";
|
||||
if ($inst[0]['site_name'])
|
||||
$site_name = (string)$inst[0]['site_name'];
|
||||
else
|
||||
$site_name = Okapi::get_normalized_site_name($site_url);
|
||||
$results[] = array(
|
||||
'site_url' => $site_url,
|
||||
'site_name' => $site_name,
|
||||
'okapi_base_url' => $okapi_base_url,
|
||||
);
|
||||
if ($site_url == Settings::get('SITE_URL'))
|
||||
$i_was_included = true;
|
||||
}
|
||||
|
||||
# If running on a local development installation, then include the local
|
||||
# installation URL.
|
||||
# If running on a local development installation, then include the local
|
||||
# installation URL.
|
||||
|
||||
if (!$i_was_included)
|
||||
{
|
||||
$results[] = array(
|
||||
'site_url' => Settings::get('SITE_URL'),
|
||||
'site_name' => "DEVELSITE",
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
);
|
||||
# Contact OKAPI developers in order to get added to the official sites list!
|
||||
}
|
||||
if (!$i_was_included)
|
||||
{
|
||||
$results[] = array(
|
||||
'site_url' => Settings::get('SITE_URL'),
|
||||
'site_name' => "DEVELSITE",
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
);
|
||||
# Contact OKAPI developers in order to get added to the official sites list!
|
||||
}
|
||||
|
||||
# Cache it for one day. Also, save a backup (valid for 30 days).
|
||||
# Cache it for one day. Also, save a backup (valid for 30 days).
|
||||
|
||||
Cache::set($cachekey, $results, 86400);
|
||||
Cache::set($backupkey, $results, 86400*30);
|
||||
}
|
||||
Cache::set($cachekey, $results, 86400);
|
||||
Cache::set($backupkey, $results, 86400*30);
|
||||
}
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,33 @@
|
||||
<xml>
|
||||
<brief>Get the list of all public OKAPI installations</brief>
|
||||
<issue-id>39</issue-id>
|
||||
<desc>
|
||||
Get the list of all public OKAPI installations. Keep in mind that
|
||||
OKAPI installations might differ slightly. If you plan on using
|
||||
multiple OKAPI installations in your application (which is a very
|
||||
good thing!) you should test it against the one with the <b>lowest</b>
|
||||
OKAPI revision number.
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>site_url</b> - URL of the Opencaching site which is running
|
||||
the OKAPI installation (usually this looks like
|
||||
"http://www.opencaching.<i>xx</i>/", where <b>xx</b> is a top
|
||||
level domain of a country).
|
||||
</li>
|
||||
<li>
|
||||
<b>site_name</b> - universal name for this site (should be fine
|
||||
for all languages),
|
||||
</li>
|
||||
<li>
|
||||
<b>okapi_base_url</b> - URL of the OKAPI installation (usually this is
|
||||
<b>site_url</b> with "okapi/" appended, but you should not assume
|
||||
that); this value is to be used as a prefix when constructing service
|
||||
method URLs.
|
||||
</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Get the list of all public OKAPI installations</brief>
|
||||
<issue-id>39</issue-id>
|
||||
<desc>
|
||||
Get the list of all public OKAPI installations. Keep in mind that
|
||||
OKAPI installations might differ slightly. If you plan on using
|
||||
multiple OKAPI installations in your application (which is a very
|
||||
good thing!) you should test it against the one with the <b>lowest</b>
|
||||
OKAPI revision number.
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>site_url</b> - URL of the Opencaching site which is running
|
||||
the OKAPI installation (usually this looks like
|
||||
"http://www.opencaching.<i>xx</i>/", where <b>xx</b> is a top
|
||||
level domain of a country).
|
||||
</li>
|
||||
<li>
|
||||
<b>site_name</b> - universal name for this site (should be fine
|
||||
for all languages),
|
||||
</li>
|
||||
<li>
|
||||
<b>okapi_base_url</b> - URL of the OKAPI installation (usually this is
|
||||
<b>site_url</b> with "okapi/" appended, but you should not assume
|
||||
that); this value is to be used as a prefix when constructing service
|
||||
method URLs.
|
||||
</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -15,48 +15,48 @@ use okapi\Settings;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cachekey = "apisrv/stats";
|
||||
$result = Cache::get($cachekey);
|
||||
if (!$result)
|
||||
{
|
||||
$result = array(
|
||||
'cache_count' => 0 + Db::select_value("
|
||||
select count(*) from caches where status in (1,2,3)
|
||||
"),
|
||||
'user_count' => 0 + Db::select_value("
|
||||
select count(*) from (
|
||||
select distinct user_id
|
||||
from cache_logs
|
||||
where
|
||||
type in (1,2)
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
UNION DISTINCT
|
||||
select distinct user_id
|
||||
from caches
|
||||
) as t;
|
||||
"),
|
||||
'apps_count' => 0 + Db::select_value("select count(*) from okapi_consumers;"),
|
||||
'apps_active' => 0 + Db::select_value("
|
||||
select count(distinct s.consumer_key)
|
||||
from
|
||||
okapi_stats_hourly s,
|
||||
okapi_consumers c
|
||||
where
|
||||
s.consumer_key = c.`key`
|
||||
and s.period_start > date_add(now(), interval -30 day)
|
||||
"),
|
||||
);
|
||||
Cache::set($cachekey, $result, 86400); # cache it for one day
|
||||
}
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cachekey = "apisrv/stats";
|
||||
$result = Cache::get($cachekey);
|
||||
if (!$result)
|
||||
{
|
||||
$result = array(
|
||||
'cache_count' => 0 + Db::select_value("
|
||||
select count(*) from caches where status in (1,2,3)
|
||||
"),
|
||||
'user_count' => 0 + Db::select_value("
|
||||
select count(*) from (
|
||||
select distinct user_id
|
||||
from cache_logs
|
||||
where
|
||||
type in (1,2)
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
UNION DISTINCT
|
||||
select distinct user_id
|
||||
from caches
|
||||
) as t;
|
||||
"),
|
||||
'apps_count' => 0 + Db::select_value("select count(*) from okapi_consumers;"),
|
||||
'apps_active' => 0 + Db::select_value("
|
||||
select count(distinct s.consumer_key)
|
||||
from
|
||||
okapi_stats_hourly s,
|
||||
okapi_consumers c
|
||||
where
|
||||
s.consumer_key = c.`key`
|
||||
and s.period_start > date_add(now(), interval -30 day)
|
||||
"),
|
||||
);
|
||||
Cache::set($cachekey, $result, 86400); # cache it for one day
|
||||
}
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
<xml>
|
||||
<brief>Get some basic stats about the site</brief>
|
||||
<issue-id>43</issue-id>
|
||||
<desc>
|
||||
Retrieve some basic statistics about this OKAPI installation.
|
||||
If you want some more stats, post a comment!
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>cache_count</b> - approximate total number of geocaches stored at this site,</li>
|
||||
<li><b>user_count</b> - approximate total number of active users of this site,</li>
|
||||
<li><b>apps_count</b> - approximate total number of all OKAPI applications (number of
|
||||
registered API Keys).</li>
|
||||
<li><b>apps_active</b> - approximate number of active OKAPI applications (the ones which issued
|
||||
at least one, non-anonymous OKAPI request during the last month).</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Get some basic stats about the site</brief>
|
||||
<issue-id>43</issue-id>
|
||||
<desc>
|
||||
Retrieve some basic statistics about this OKAPI installation.
|
||||
If you want some more stats, post a comment!
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>cache_count</b> - approximate total number of geocaches stored at this site,</li>
|
||||
<li><b>user_count</b> - approximate total number of active users of this site,</li>
|
||||
<li><b>apps_count</b> - approximate total number of all OKAPI applications (number of
|
||||
registered API Keys).</li>
|
||||
<li><b>apps_active</b> - approximate number of active OKAPI applications (the ones which issued
|
||||
at least one, non-anonymous OKAPI request during the last month).</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -18,272 +18,272 @@ use SimpleXMLElement;
|
||||
|
||||
class AttrHelper
|
||||
{
|
||||
/**
|
||||
* By default, when DEBUG mode is enabled, the attributes.xml file is
|
||||
* reloaded practically on every request. If you don't want that, you can
|
||||
* temporarilly disable this behavior by settings this to false.
|
||||
*/
|
||||
private static $RELOAD_ON_DEBUG = true;
|
||||
/**
|
||||
* By default, when DEBUG mode is enabled, the attributes.xml file is
|
||||
* reloaded practically on every request. If you don't want that, you can
|
||||
* temporarilly disable this behavior by settings this to false.
|
||||
*/
|
||||
private static $RELOAD_ON_DEBUG = true;
|
||||
|
||||
private static $attr_dict = null;
|
||||
private static $attr_dict = null;
|
||||
|
||||
/**
|
||||
* Return the cache key suffix to be used for caching. This should be used
|
||||
* In order for the $RELOAD_ON_DEBUG to work properly when switching to/from
|
||||
* DEBUG mode.
|
||||
*/
|
||||
private static function cache_key_suffix()
|
||||
{
|
||||
return (self::$RELOAD_ON_DEBUG) ? "#DBG" : "";
|
||||
}
|
||||
/**
|
||||
* Return the cache key suffix to be used for caching. This should be used
|
||||
* In order for the $RELOAD_ON_DEBUG to work properly when switching to/from
|
||||
* DEBUG mode.
|
||||
*/
|
||||
private static function cache_key_suffix()
|
||||
{
|
||||
return (self::$RELOAD_ON_DEBUG) ? "#DBG" : "";
|
||||
}
|
||||
|
||||
/** Return the timeout to be used for attribute caching. */
|
||||
private static function ttl()
|
||||
{
|
||||
return (Settings::get('DEBUG') && self::$RELOAD_ON_DEBUG) ? 2 : 86400;
|
||||
}
|
||||
/** Return the timeout to be used for attribute caching. */
|
||||
private static function ttl()
|
||||
{
|
||||
return (Settings::get('DEBUG') && self::$RELOAD_ON_DEBUG) ? 2 : 86400;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces an immediate refresh of the current attributes from the
|
||||
* attribute-definitions.xml file.
|
||||
*/
|
||||
public static function refresh_now()
|
||||
{
|
||||
try
|
||||
{
|
||||
$path = $GLOBALS['rootpath']."okapi/services/attrs/attribute-definitions.xml";
|
||||
$xml = file_get_contents($path);
|
||||
self::refresh_from_string($xml);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# Failed to read or parse the file (i.e. after a syntax error was
|
||||
# commited). Let's check when the last successful parse occured.
|
||||
/**
|
||||
* Forces an immediate refresh of the current attributes from the
|
||||
* attribute-definitions.xml file.
|
||||
*/
|
||||
public static function refresh_now()
|
||||
{
|
||||
try
|
||||
{
|
||||
$path = $GLOBALS['rootpath']."okapi/services/attrs/attribute-definitions.xml";
|
||||
$xml = file_get_contents($path);
|
||||
self::refresh_from_string($xml);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# Failed to read or parse the file (i.e. after a syntax error was
|
||||
# commited). Let's check when the last successful parse occured.
|
||||
|
||||
self::init_from_cache(false);
|
||||
self::init_from_cache(false);
|
||||
|
||||
if (self::$attr_dict === null)
|
||||
{
|
||||
# That's bad! We don't have ANY copy of the data AND we failed
|
||||
# to parse it. We will use a fake, empty data.
|
||||
if (self::$attr_dict === null)
|
||||
{
|
||||
# That's bad! We don't have ANY copy of the data AND we failed
|
||||
# to parse it. We will use a fake, empty data.
|
||||
|
||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||
$cachedvalue = array(
|
||||
'attr_dict' => array(),
|
||||
);
|
||||
Cache::set($cache_key, $cachedvalue, self::ttl());
|
||||
}
|
||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||
$cachedvalue = array(
|
||||
'attr_dict' => array(),
|
||||
);
|
||||
Cache::set($cache_key, $cachedvalue, self::ttl());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh all attributes from the given XML. Usually, this file is
|
||||
* downloaded from Google Code (using refresh_now).
|
||||
*/
|
||||
public static function refresh_from_string($xml)
|
||||
{
|
||||
/* The attribute-definitions.xml file defines relationships between
|
||||
* attributes originating from various OC installations. Each
|
||||
* installation uses internal IDs of its own. Which "attribute schema"
|
||||
* is being used in THIS installation? */
|
||||
/**
|
||||
* Refresh all attributes from the given XML. Usually, this file is
|
||||
* downloaded from Google Code (using refresh_now).
|
||||
*/
|
||||
public static function refresh_from_string($xml)
|
||||
{
|
||||
/* The attribute-definitions.xml file defines relationships between
|
||||
* attributes originating from various OC installations. Each
|
||||
* installation uses internal IDs of its own. Which "attribute schema"
|
||||
* is being used in THIS installation? */
|
||||
|
||||
$my_schema = Settings::get('ORIGIN_URL');
|
||||
$my_schema = Settings::get('ORIGIN_URL');
|
||||
|
||||
$doc = simplexml_load_string($xml);
|
||||
$cachedvalue = array(
|
||||
'attr_dict' => array(),
|
||||
);
|
||||
$doc = simplexml_load_string($xml);
|
||||
$cachedvalue = array(
|
||||
'attr_dict' => array(),
|
||||
);
|
||||
|
||||
# Build cache attributes dictionary
|
||||
# Build cache attributes dictionary
|
||||
|
||||
$all_internal_ids = array();
|
||||
foreach ($doc->attr as $attrnode)
|
||||
{
|
||||
$attr = array(
|
||||
'acode' => (string)$attrnode['acode'],
|
||||
'gc_equivs' => array(),
|
||||
'internal_id' => null,
|
||||
'names' => array(),
|
||||
'descriptions' => array(),
|
||||
'is_discontinued' => true
|
||||
);
|
||||
foreach ($attrnode->groundspeak as $gsnode)
|
||||
{
|
||||
$attr['gc_equivs'][] = array(
|
||||
'id' => (int)$gsnode['id'],
|
||||
'inc' => in_array((string)$gsnode['inc'], array("true", "1")) ? 1 : 0,
|
||||
'name' => (string)$gsnode['name']
|
||||
);
|
||||
}
|
||||
foreach ($attrnode->opencaching as $ocnode)
|
||||
{
|
||||
/* If it is used by at least one OC node, then it's NOT discontinued. */
|
||||
$attr['is_discontinued'] = false;
|
||||
$all_internal_ids = array();
|
||||
foreach ($doc->attr as $attrnode)
|
||||
{
|
||||
$attr = array(
|
||||
'acode' => (string)$attrnode['acode'],
|
||||
'gc_equivs' => array(),
|
||||
'internal_id' => null,
|
||||
'names' => array(),
|
||||
'descriptions' => array(),
|
||||
'is_discontinued' => true
|
||||
);
|
||||
foreach ($attrnode->groundspeak as $gsnode)
|
||||
{
|
||||
$attr['gc_equivs'][] = array(
|
||||
'id' => (int)$gsnode['id'],
|
||||
'inc' => in_array((string)$gsnode['inc'], array("true", "1")) ? 1 : 0,
|
||||
'name' => (string)$gsnode['name']
|
||||
);
|
||||
}
|
||||
foreach ($attrnode->opencaching as $ocnode)
|
||||
{
|
||||
/* If it is used by at least one OC node, then it's NOT discontinued. */
|
||||
$attr['is_discontinued'] = false;
|
||||
|
||||
if ((string)$ocnode['schema'] == $my_schema)
|
||||
{
|
||||
/* It is used by THIS OC node. */
|
||||
if ((string)$ocnode['schema'] == $my_schema)
|
||||
{
|
||||
/* It is used by THIS OC node. */
|
||||
|
||||
$internal_id = (int)$ocnode['id'];
|
||||
if (isset($all_internal_ids[$internal_id]))
|
||||
throw new Exception("The internal attribute ".$internal_id.
|
||||
" has multiple assigments to OKAPI attributes.");
|
||||
$all_internal_ids[$internal_id] = true;
|
||||
if (!is_null($attr['internal_id']))
|
||||
throw new Exception("There are multiple internal IDs for the ".
|
||||
$attr['acode']." attribute.");
|
||||
$attr['internal_id'] = $internal_id;
|
||||
}
|
||||
}
|
||||
foreach ($attrnode->lang as $langnode)
|
||||
{
|
||||
$lang = (string)$langnode['id'];
|
||||
foreach ($langnode->name as $namenode)
|
||||
{
|
||||
if (isset($attr['names'][$lang]))
|
||||
throw new Exception("Duplicate ".$lang." name of attribute ".$attr['acode']);
|
||||
$attr['names'][$lang] = (string)$namenode;
|
||||
}
|
||||
foreach ($langnode->desc as $descnode)
|
||||
{
|
||||
if (isset($attr['descriptions'][$lang]))
|
||||
throw new Exception("Duplicate ".$lang." description of attribute ".$attr['acode']);
|
||||
$xml = $descnode->asxml(); /* contains "<desc>" and "</desc>" */
|
||||
$innerxml = preg_replace("/(^[^>]+>)|(<[^<]+$)/us", "", $xml);
|
||||
$attr['descriptions'][$lang] = self::cleanup_string($innerxml);
|
||||
}
|
||||
}
|
||||
$cachedvalue['attr_dict'][$attr['acode']] = $attr;
|
||||
}
|
||||
$internal_id = (int)$ocnode['id'];
|
||||
if (isset($all_internal_ids[$internal_id]))
|
||||
throw new Exception("The internal attribute ".$internal_id.
|
||||
" has multiple assigments to OKAPI attributes.");
|
||||
$all_internal_ids[$internal_id] = true;
|
||||
if (!is_null($attr['internal_id']))
|
||||
throw new Exception("There are multiple internal IDs for the ".
|
||||
$attr['acode']." attribute.");
|
||||
$attr['internal_id'] = $internal_id;
|
||||
}
|
||||
}
|
||||
foreach ($attrnode->lang as $langnode)
|
||||
{
|
||||
$lang = (string)$langnode['id'];
|
||||
foreach ($langnode->name as $namenode)
|
||||
{
|
||||
if (isset($attr['names'][$lang]))
|
||||
throw new Exception("Duplicate ".$lang." name of attribute ".$attr['acode']);
|
||||
$attr['names'][$lang] = (string)$namenode;
|
||||
}
|
||||
foreach ($langnode->desc as $descnode)
|
||||
{
|
||||
if (isset($attr['descriptions'][$lang]))
|
||||
throw new Exception("Duplicate ".$lang." description of attribute ".$attr['acode']);
|
||||
$xml = $descnode->asxml(); /* contains "<desc>" and "</desc>" */
|
||||
$innerxml = preg_replace("/(^[^>]+>)|(<[^<]+$)/us", "", $xml);
|
||||
$attr['descriptions'][$lang] = self::cleanup_string($innerxml);
|
||||
}
|
||||
}
|
||||
$cachedvalue['attr_dict'][$attr['acode']] = $attr;
|
||||
}
|
||||
|
||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||
Cache::set($cache_key, $cachedvalue, self::ttl());
|
||||
self::$attr_dict = $cachedvalue['attr_dict'];
|
||||
}
|
||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||
Cache::set($cache_key, $cachedvalue, self::ttl());
|
||||
self::$attr_dict = $cachedvalue['attr_dict'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Object to be used for forward-compatibility (see the attributes method).
|
||||
*/
|
||||
public static function get_unknown_placeholder($acode)
|
||||
{
|
||||
return array(
|
||||
'acode' => $acode,
|
||||
'gc_equivs' => array(),
|
||||
'internal_id' => null,
|
||||
'names' => array(
|
||||
'en' => "Unknown attribute"
|
||||
),
|
||||
'descriptions' => array(
|
||||
'en' => (
|
||||
"This attribute ($acode) is unknown at ".Okapi::get_normalized_site_name().
|
||||
". It might not exist, or it may be a new attribute, recognized ".
|
||||
"only in newer OKAPI installations. Perhaps ".Okapi::get_normalized_site_name().
|
||||
" needs to have its OKAPI updated?"
|
||||
)
|
||||
),
|
||||
'is_discontinued' => true
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Object to be used for forward-compatibility (see the attributes method).
|
||||
*/
|
||||
public static function get_unknown_placeholder($acode)
|
||||
{
|
||||
return array(
|
||||
'acode' => $acode,
|
||||
'gc_equivs' => array(),
|
||||
'internal_id' => null,
|
||||
'names' => array(
|
||||
'en' => "Unknown attribute"
|
||||
),
|
||||
'descriptions' => array(
|
||||
'en' => (
|
||||
"This attribute ($acode) is unknown at ".Okapi::get_normalized_site_name().
|
||||
". It might not exist, or it may be a new attribute, recognized ".
|
||||
"only in newer OKAPI installations. Perhaps ".Okapi::get_normalized_site_name().
|
||||
" needs to have its OKAPI updated?"
|
||||
)
|
||||
),
|
||||
'is_discontinued' => true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all the internal attributes (if not yet initialized). This
|
||||
* loads attribute values from the cache. If they are not present in the
|
||||
* cache, it will read and parse them from attribute-definitions.xml file.
|
||||
*/
|
||||
private static function init_from_cache($allow_refreshing=true)
|
||||
{
|
||||
if (self::$attr_dict !== null)
|
||||
{
|
||||
/* Already initialized. */
|
||||
return;
|
||||
}
|
||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||
$cachedvalue = Cache::get($cache_key);
|
||||
if ($cachedvalue === null)
|
||||
{
|
||||
# I.e. after Okapi::$revision is changed, or cache got invalidated.
|
||||
/**
|
||||
* Initialize all the internal attributes (if not yet initialized). This
|
||||
* loads attribute values from the cache. If they are not present in the
|
||||
* cache, it will read and parse them from attribute-definitions.xml file.
|
||||
*/
|
||||
private static function init_from_cache($allow_refreshing=true)
|
||||
{
|
||||
if (self::$attr_dict !== null)
|
||||
{
|
||||
/* Already initialized. */
|
||||
return;
|
||||
}
|
||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||
$cachedvalue = Cache::get($cache_key);
|
||||
if ($cachedvalue === null)
|
||||
{
|
||||
# I.e. after Okapi::$revision is changed, or cache got invalidated.
|
||||
|
||||
if ($allow_refreshing)
|
||||
{
|
||||
self::refresh_now();
|
||||
self::init_from_cache(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cachedvalue = array(
|
||||
'attr_dict' => array(),
|
||||
);
|
||||
}
|
||||
}
|
||||
self::$attr_dict = $cachedvalue['attr_dict'];
|
||||
}
|
||||
if ($allow_refreshing)
|
||||
{
|
||||
self::refresh_now();
|
||||
self::init_from_cache(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cachedvalue = array(
|
||||
'attr_dict' => array(),
|
||||
);
|
||||
}
|
||||
}
|
||||
self::$attr_dict = $cachedvalue['attr_dict'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a dictionary of all attributes. The format is INTERNAL and PRIVATE,
|
||||
* it is NOT the same as in the "attributes" method (but it is quite similar).
|
||||
*/
|
||||
public static function get_attrdict()
|
||||
{
|
||||
self::init_from_cache();
|
||||
return self::$attr_dict;
|
||||
}
|
||||
/**
|
||||
* Return a dictionary of all attributes. The format is INTERNAL and PRIVATE,
|
||||
* it is NOT the same as in the "attributes" method (but it is quite similar).
|
||||
*/
|
||||
public static function get_attrdict()
|
||||
{
|
||||
self::init_from_cache();
|
||||
return self::$attr_dict;
|
||||
}
|
||||
|
||||
/** "\n\t\tBla blabla\n\t\t<b>bla</b>bla.\n\t" => "Bla blabla <b>bla</b>bla." */
|
||||
private static function cleanup_string($s)
|
||||
{
|
||||
return preg_replace('/(^\s+)|(\s+$)/us', "", preg_replace('/\s+/us', " ", $s));
|
||||
}
|
||||
/** "\n\t\tBla blabla\n\t\t<b>bla</b>bla.\n\t" => "Bla blabla <b>bla</b>bla." */
|
||||
private static function cleanup_string($s)
|
||||
{
|
||||
return preg_replace('/(^\s+)|(\s+$)/us', "", preg_replace('/\s+/us', " ", $s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mapping table between internal attribute id => OKAPI A-code.
|
||||
* The result is cached!
|
||||
*/
|
||||
public static function get_internal_id_to_acode_mapping()
|
||||
{
|
||||
static $mapping = null;
|
||||
if ($mapping !== null)
|
||||
return $mapping;
|
||||
/**
|
||||
* Get the mapping table between internal attribute id => OKAPI A-code.
|
||||
* The result is cached!
|
||||
*/
|
||||
public static function get_internal_id_to_acode_mapping()
|
||||
{
|
||||
static $mapping = null;
|
||||
if ($mapping !== null)
|
||||
return $mapping;
|
||||
|
||||
$cache_key = "attrhelper/id2acode/".Okapi::$revision.self::cache_key_suffix();
|
||||
$mapping = Cache::get($cache_key);
|
||||
if (!$mapping)
|
||||
{
|
||||
self::init_from_cache();
|
||||
$mapping = array();
|
||||
foreach (self::$attr_dict as $acode => &$attr_ref)
|
||||
$mapping[$attr_ref['internal_id']] = $acode;
|
||||
Cache::set($cache_key, $mapping, self::ttl());
|
||||
}
|
||||
return $mapping;
|
||||
}
|
||||
$cache_key = "attrhelper/id2acode/".Okapi::$revision.self::cache_key_suffix();
|
||||
$mapping = Cache::get($cache_key);
|
||||
if (!$mapping)
|
||||
{
|
||||
self::init_from_cache();
|
||||
$mapping = array();
|
||||
foreach (self::$attr_dict as $acode => &$attr_ref)
|
||||
$mapping[$attr_ref['internal_id']] = $acode;
|
||||
Cache::set($cache_key, $mapping, self::ttl());
|
||||
}
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mapping: A-codes => attribute name. The language for the name
|
||||
* is selected based on the $langpref parameter. The result is cached!
|
||||
*/
|
||||
public static function get_acode_to_name_mapping($langpref)
|
||||
{
|
||||
static $mapping = null;
|
||||
if ($mapping !== null)
|
||||
return $mapping;
|
||||
/**
|
||||
* Get the mapping: A-codes => attribute name. The language for the name
|
||||
* is selected based on the $langpref parameter. The result is cached!
|
||||
*/
|
||||
public static function get_acode_to_name_mapping($langpref)
|
||||
{
|
||||
static $mapping = null;
|
||||
if ($mapping !== null)
|
||||
return $mapping;
|
||||
|
||||
$cache_key = md5(serialize(array("attrhelper/acode2name", $langpref,
|
||||
Okapi::$revision, self::cache_key_suffix())));
|
||||
$mapping = Cache::get($cache_key);
|
||||
if (!$mapping)
|
||||
{
|
||||
self::init_from_cache();
|
||||
$mapping = array();
|
||||
foreach (self::$attr_dict as $acode => &$attr_ref)
|
||||
{
|
||||
$mapping[$acode] = Okapi::pick_best_language(
|
||||
$attr_ref['names'], $langpref);
|
||||
}
|
||||
Cache::set($cache_key, $mapping, self::ttl());
|
||||
}
|
||||
return $mapping;
|
||||
}
|
||||
$cache_key = md5(serialize(array("attrhelper/acode2name", $langpref,
|
||||
Okapi::$revision, self::cache_key_suffix())));
|
||||
$mapping = Cache::get($cache_key);
|
||||
if (!$mapping)
|
||||
{
|
||||
self::init_from_cache();
|
||||
$mapping = array();
|
||||
foreach (self::$attr_dict as $acode => &$attr_ref)
|
||||
{
|
||||
$mapping[$acode] = Okapi::pick_best_language(
|
||||
$attr_ref['names'], $langpref);
|
||||
}
|
||||
Cache::set($cache_key, $mapping, self::ttl());
|
||||
}
|
||||
return $mapping;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,45 +17,45 @@ use okapi\services\attrs\AttrHelper;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Read the parameters.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Read the parameters.
|
||||
|
||||
$acode = $request->get_parameter('acode');
|
||||
if ($acode === null) throw new ParamMissing('acode');
|
||||
$acode = $request->get_parameter('acode');
|
||||
if ($acode === null) throw new ParamMissing('acode');
|
||||
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "name";
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "name";
|
||||
|
||||
$forward_compatible = $request->get_parameter('forward_compatible');
|
||||
if (!$forward_compatible) $forward_compatible = "true";
|
||||
$forward_compatible = $request->get_parameter('forward_compatible');
|
||||
if (!$forward_compatible) $forward_compatible = "true";
|
||||
|
||||
# Pass them all to the attributes method.
|
||||
# Pass them all to the attributes method.
|
||||
|
||||
$params = array(
|
||||
'acodes' => $acode,
|
||||
'langpref' => $langpref,
|
||||
'fields' => $fields,
|
||||
'forward_compatible' => $forward_compatible
|
||||
);
|
||||
$results = OkapiServiceRunner::call('services/attrs/attributes',
|
||||
new OkapiInternalRequest($request->consumer, $request->token, $params));
|
||||
$result = $results[$acode];
|
||||
if ($result === null)
|
||||
{
|
||||
/* Note, this can happen only when $forward_compatible is false. */
|
||||
throw new InvalidParam('acode', "Unknown A-code.");
|
||||
}
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$params = array(
|
||||
'acodes' => $acode,
|
||||
'langpref' => $langpref,
|
||||
'fields' => $fields,
|
||||
'forward_compatible' => $forward_compatible
|
||||
);
|
||||
$results = OkapiServiceRunner::call('services/attrs/attributes',
|
||||
new OkapiInternalRequest($request->consumer, $request->token, $params));
|
||||
$result = $results[$acode];
|
||||
if ($result === null)
|
||||
{
|
||||
/* Note, this can happen only when $forward_compatible is false. */
|
||||
throw new InvalidParam('acode', "Unknown A-code.");
|
||||
}
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,134 +1,134 @@
|
||||
<xml>
|
||||
<brief>Retrieve data on a single attribute</brief>
|
||||
<issue-id>268</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve data on a single OKAPI geocache-attribute.</p>
|
||||
|
||||
<p>OKAPI attributes are identified by an unique ID called an <b>A-code</b>.
|
||||
All OKAPI attributes are shared among all OKAPI servers. Once an attribute is
|
||||
published (e.g. via the <b>attribute_index</b> method), it won't
|
||||
disappear in any of the future OKAPI revisions, nor will its meaning change.
|
||||
Some attributes may get discontinued in the future, but they will remain accessible
|
||||
by their original A-code.</p>
|
||||
</desc>
|
||||
<req name='acode'>
|
||||
The A-code of the attribute you're interested in.
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for fields like
|
||||
<b>name</b> and <b>description</b>.</p>
|
||||
</opt>
|
||||
<opt name='fields' default='name'>
|
||||
<p>Pipe-separated list of field names which you are interested with.
|
||||
See below for the list of available fields.</p>
|
||||
</opt>
|
||||
<opt name='forward_compatible' default='true'>
|
||||
By default, OKAPI will return an empty placeholder if you ask for an
|
||||
unknown attribute. If you'd like to catch such errors and handle them
|
||||
differently, then you may change this behavior by setting this parameter
|
||||
to <b>false</b>. Then, OKAPI will return HTTP 400 error response,
|
||||
instead of the placeholder (note that it behaves differently in the
|
||||
<b>attributes</b> method).
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected in the <b>fields</b>
|
||||
parameter. Available fields:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p><b>acode</b> - string, the A-code. Unique identifier of the
|
||||
attribute.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>name</b> - plaintext string, name of the attribute (language is
|
||||
selected based on your <b>langpref</b> parameter),</p>
|
||||
|
||||
<p>If you think your language is missing, then feel free to add missing
|
||||
translations directly to OKAPI repository. See
|
||||
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>names</b> - a dictionary of all known names of the attribute, in
|
||||
various languages (ISO 639-1 language code is used as dictionary
|
||||
key).</p>
|
||||
|
||||
<p>If you think your language is missing, then feel free to add missing
|
||||
translations directly to OKAPI repository. See
|
||||
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>description</b> - HTML string, description of the attribute (language is
|
||||
selected based on your <b>langpref</b> parameter),
|
||||
|
||||
<p>If you think your language is missing, then feel free to add missing
|
||||
translations directly to OKAPI repository. See
|
||||
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>descriptions</b> - a dictionary of all known descriptions of the
|
||||
attribute, in various languages (ISO 639-1 language code is used as
|
||||
dictionary key).</p>
|
||||
|
||||
<p>If you think your language is missing, then feel free to add missing
|
||||
translations directly to OKAPI repository. See
|
||||
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>gc_equivs</b> - a list of Geocaching.com (Groundspeak)
|
||||
attributes, which have exactly the same (or a very similar) meaning. Each
|
||||
attribute is described as a dictionary of the following structure:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>id</b> - ID of the Geocaching.com attribute,</li>
|
||||
<li>
|
||||
<b>inc</b> - integer, either 1 or 0. See Geocaching.com's
|
||||
XSD for details on its meaning,
|
||||
</li>
|
||||
<li>
|
||||
<b>name</b> - the name of the attribute (as it is included
|
||||
in Geocaching.com GPX files).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Note that one gc_equivs list may have multiple items on it, and
|
||||
that one Geocaching.com ID may be present in many gc_equivs.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_locally_used</b> - boolean, indicates if the attribute is <i>currently</i>
|
||||
used by <i>this</i> Opencaching server. Or, to be more specific, <b>true</b>
|
||||
means that the attribute can currently be included in the <b>attr_acodes</b> field
|
||||
of the <b>geocache</b> method in this OKAPI installation.</p>
|
||||
|
||||
<p>Note that this flag can change in time. Some attributes may get
|
||||
introduced into other installations, whereas other attributes may
|
||||
(temporarily or permanently) stop being used. In general, we are aiming
|
||||
towards global unification of all attributes between all OC nodes,
|
||||
but this process will take time (and probably it will never
|
||||
be 100% complete).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>local_icon_url</b> - an URL pointing to an image associated with
|
||||
this particular attribute in the local OC server, <b>or null</b> if the
|
||||
current server does not have any image for this attribute.</p>
|
||||
|
||||
<p>Please note, that each OC server uses a different image set for their
|
||||
attributes. All these images come in various sizes and can change over time.
|
||||
In other words, if you want to use this attribute, then you must always be
|
||||
prepared to receive <b>null</b>, or an image of unexpected dimensions.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_discontinued</b> - boolean, indicates if the attribute is discontinued.
|
||||
This means that it is no longer in use at OC servers which run current OKAPI
|
||||
versions, i.e. geocaches are no longer tagged with this attribute. However,
|
||||
it may still be in use at servers which have not been updated yet to the
|
||||
current OKAPI version.</p>
|
||||
|
||||
<p><b>Important:</b> This flag can change in time. Discontinued attributes can
|
||||
"come back to life" later. You can never be 100% sure you will not
|
||||
encounter them in OKAPI responses, so this field is purely informative.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Retrieve data on a single attribute</brief>
|
||||
<issue-id>268</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve data on a single OKAPI geocache-attribute.</p>
|
||||
|
||||
<p>OKAPI attributes are identified by an unique ID called an <b>A-code</b>.
|
||||
All OKAPI attributes are shared among all OKAPI servers. Once an attribute is
|
||||
published (e.g. via the <b>attribute_index</b> method), it won't
|
||||
disappear in any of the future OKAPI revisions, nor will its meaning change.
|
||||
Some attributes may get discontinued in the future, but they will remain accessible
|
||||
by their original A-code.</p>
|
||||
</desc>
|
||||
<req name='acode'>
|
||||
The A-code of the attribute you're interested in.
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for fields like
|
||||
<b>name</b> and <b>description</b>.</p>
|
||||
</opt>
|
||||
<opt name='fields' default='name'>
|
||||
<p>Pipe-separated list of field names which you are interested with.
|
||||
See below for the list of available fields.</p>
|
||||
</opt>
|
||||
<opt name='forward_compatible' default='true'>
|
||||
By default, OKAPI will return an empty placeholder if you ask for an
|
||||
unknown attribute. If you'd like to catch such errors and handle them
|
||||
differently, then you may change this behavior by setting this parameter
|
||||
to <b>false</b>. Then, OKAPI will return HTTP 400 error response,
|
||||
instead of the placeholder (note that it behaves differently in the
|
||||
<b>attributes</b> method).
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected in the <b>fields</b>
|
||||
parameter. Available fields:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p><b>acode</b> - string, the A-code. Unique identifier of the
|
||||
attribute.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>name</b> - plaintext string, name of the attribute (language is
|
||||
selected based on your <b>langpref</b> parameter),</p>
|
||||
|
||||
<p>If you think your language is missing, then feel free to add missing
|
||||
translations directly to OKAPI repository. See
|
||||
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>names</b> - a dictionary of all known names of the attribute, in
|
||||
various languages (ISO 639-1 language code is used as dictionary
|
||||
key).</p>
|
||||
|
||||
<p>If you think your language is missing, then feel free to add missing
|
||||
translations directly to OKAPI repository. See
|
||||
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>description</b> - HTML string, description of the attribute (language is
|
||||
selected based on your <b>langpref</b> parameter),
|
||||
|
||||
<p>If you think your language is missing, then feel free to add missing
|
||||
translations directly to OKAPI repository. See
|
||||
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>descriptions</b> - a dictionary of all known descriptions of the
|
||||
attribute, in various languages (ISO 639-1 language code is used as
|
||||
dictionary key).</p>
|
||||
|
||||
<p>If you think your language is missing, then feel free to add missing
|
||||
translations directly to OKAPI repository. See
|
||||
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>gc_equivs</b> - a list of Geocaching.com (Groundspeak)
|
||||
attributes, which have exactly the same (or a very similar) meaning. Each
|
||||
attribute is described as a dictionary of the following structure:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>id</b> - ID of the Geocaching.com attribute,</li>
|
||||
<li>
|
||||
<b>inc</b> - integer, either 1 or 0. See Geocaching.com's
|
||||
XSD for details on its meaning,
|
||||
</li>
|
||||
<li>
|
||||
<b>name</b> - the name of the attribute (as it is included
|
||||
in Geocaching.com GPX files).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Note that one gc_equivs list may have multiple items on it, and
|
||||
that one Geocaching.com ID may be present in many gc_equivs.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_locally_used</b> - boolean, indicates if the attribute is <i>currently</i>
|
||||
used by <i>this</i> Opencaching server. Or, to be more specific, <b>true</b>
|
||||
means that the attribute can currently be included in the <b>attr_acodes</b> field
|
||||
of the <b>geocache</b> method in this OKAPI installation.</p>
|
||||
|
||||
<p>Note that this flag can change in time. Some attributes may get
|
||||
introduced into other installations, whereas other attributes may
|
||||
(temporarily or permanently) stop being used. In general, we are aiming
|
||||
towards global unification of all attributes between all OC nodes,
|
||||
but this process will take time (and probably it will never
|
||||
be 100% complete).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>local_icon_url</b> - an URL pointing to an image associated with
|
||||
this particular attribute in the local OC server, <b>or null</b> if the
|
||||
current server does not have any image for this attribute.</p>
|
||||
|
||||
<p>Please note, that each OC server uses a different image set for their
|
||||
attributes. All these images come in various sizes and can change over time.
|
||||
In other words, if you want to use this attribute, then you must always be
|
||||
prepared to receive <b>null</b>, or an image of unexpected dimensions.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_discontinued</b> - boolean, indicates if the attribute is discontinued.
|
||||
This means that it is no longer in use at OC servers which run current OKAPI
|
||||
versions, i.e. geocaches are no longer tagged with this attribute. However,
|
||||
it may still be in use at servers which have not been updated yet to the
|
||||
current OKAPI version.</p>
|
||||
|
||||
<p><b>Important:</b> This flag can change in time. Discontinued attributes can
|
||||
"come back to life" later. You can never be 100% sure you will not
|
||||
encounter them in OKAPI responses, so this field is purely informative.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -18,56 +18,56 @@ use okapi\services\attrs\AttrHelper;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Read the parameters.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Read the parameters.
|
||||
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "name";
|
||||
$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");
|
||||
$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.
|
||||
# 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
$acodes[] = $acode;
|
||||
}
|
||||
|
||||
# Retrieve the attribute objects and return the results.
|
||||
# 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
<xml>
|
||||
<brief>Get the list of all OKAPI attributes (A-codes)</brief>
|
||||
<issue-id>270</issue-id>
|
||||
<desc>
|
||||
<p>This method returns <b>all</b> currently defined OKAPI geocache-attributes.
|
||||
It is useful when you want to cache the data on the client-side.</p>
|
||||
|
||||
<p>Keep in mind that the number of attributes will grow. Hence, <b>if your application
|
||||
uses multiple OKAPI servers, then it's best to use one of the frequently
|
||||
updated servers for pre-caching attribute data</b> (currently, Opencaching.PL
|
||||
is the most frequently updated installation). Also, you should never assume
|
||||
that you have the complete list cached: A new attribute may be created at any time!</p>
|
||||
|
||||
<p>Once an attribute is published via this method, it won't disappear, nor
|
||||
will its meaning change (names and descriptions can be slightly altered though).</p>
|
||||
</desc>
|
||||
<opt name='langpref' default='en'>
|
||||
Works the same as in the <b>attribute</b> method.
|
||||
</opt>
|
||||
<opt name='fields' default='name'>
|
||||
Works the same as in the <b>attribute</b> method.
|
||||
</opt>
|
||||
<opt name='only_locally_used' default='false'>
|
||||
<p>By default, all known attributes are returned - including those which
|
||||
were used a couple of years back, or those which are used by other OC nodes
|
||||
(and may perhaps be used by the local OC node in the future). If you're
|
||||
interested only in the attributes *currently used* within *this* Opencaching
|
||||
installation, then you may set this parameter to <b>true</b>.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
A dictionary. All A-codes will be mapped to dictionary keys, and
|
||||
each value will be an object, as described in the <b>attribute</b> method.
|
||||
</returns>
|
||||
<brief>Get the list of all OKAPI attributes (A-codes)</brief>
|
||||
<issue-id>270</issue-id>
|
||||
<desc>
|
||||
<p>This method returns <b>all</b> currently defined OKAPI geocache-attributes.
|
||||
It is useful when you want to cache the data on the client-side.</p>
|
||||
|
||||
<p>Keep in mind that the number of attributes will grow. Hence, <b>if your application
|
||||
uses multiple OKAPI servers, then it's best to use one of the frequently
|
||||
updated servers for pre-caching attribute data</b> (currently, Opencaching.PL
|
||||
is the most frequently updated installation). Also, you should never assume
|
||||
that you have the complete list cached: A new attribute may be created at any time!</p>
|
||||
|
||||
<p>Once an attribute is published via this method, it won't disappear, nor
|
||||
will its meaning change (names and descriptions can be slightly altered though).</p>
|
||||
</desc>
|
||||
<opt name='langpref' default='en'>
|
||||
Works the same as in the <b>attribute</b> method.
|
||||
</opt>
|
||||
<opt name='fields' default='name'>
|
||||
Works the same as in the <b>attribute</b> method.
|
||||
</opt>
|
||||
<opt name='only_locally_used' default='false'>
|
||||
<p>By default, all known attributes are returned - including those which
|
||||
were used a couple of years back, or those which are used by other OC nodes
|
||||
(and may perhaps be used by the local OC node in the future). If you're
|
||||
interested only in the attributes *currently used* within *this* Opencaching
|
||||
installation, then you may set this parameter to <b>true</b>.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
A dictionary. All A-codes will be mapped to dictionary keys, and
|
||||
each value will be an object, as described in the <b>attribute</b> method.
|
||||
</returns>
|
||||
</xml>
|
@ -18,120 +18,120 @@ use okapi\Db;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
private static $valid_field_names = array(
|
||||
'acode', 'name', 'names', 'description', 'descriptions', 'gc_equivs',
|
||||
'is_locally_used', 'is_deprecated', 'local_icon_url', 'is_discontinued'
|
||||
);
|
||||
private static $valid_field_names = array(
|
||||
'acode', 'name', 'names', 'description', 'descriptions', 'gc_equivs',
|
||||
'is_locally_used', 'is_deprecated', 'local_icon_url', 'is_discontinued'
|
||||
);
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Read the parameters.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Read the parameters.
|
||||
|
||||
$acodes = $request->get_parameter('acodes');
|
||||
if (!$acodes) throw new ParamMissing('acodes');
|
||||
$acodes = explode("|", $acodes);
|
||||
$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);
|
||||
$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.");
|
||||
}
|
||||
$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");
|
||||
$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).
|
||||
# Load the attributes (all of them).
|
||||
|
||||
require_once 'attr_helper.inc.php';
|
||||
$attrdict = AttrHelper::get_attrdict();
|
||||
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.
|
||||
# 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! */
|
||||
$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;
|
||||
}
|
||||
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.
|
||||
# Fill langpref-specific fields.
|
||||
|
||||
$attr['name'] = Okapi::pick_best_language($attr['names'], $langpref);
|
||||
$attr['description'] = Okapi::pick_best_language($attr['descriptions'], $langpref);
|
||||
$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).
|
||||
# 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
|
||||
$attr['is_locally_used'] = ($attr['internal_id'] !== null);
|
||||
$attr['is_deprecated'] = $attr['is_discontinued']; // deprecated and undocumetned field, see issue 70
|
||||
|
||||
# Add to results.
|
||||
# Add to results.
|
||||
|
||||
$results[$acode] = $attr;
|
||||
}
|
||||
$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 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("
|
||||
select id, icon_large
|
||||
from cache_attrib
|
||||
");
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (in_array('local_icon_url', $fields))
|
||||
{
|
||||
$tmp = Db::select_all("
|
||||
select id, icon_large
|
||||
from cache_attrib
|
||||
");
|
||||
$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.
|
||||
# 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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,30 @@
|
||||
<xml>
|
||||
<brief>Retrieve data on multiple attributes at once</brief>
|
||||
<issue-id>269</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the <b>attribute</b> method, but
|
||||
with multiple A-codes instead of only one. Read the docs for
|
||||
the <b>attribute</b> method first!</p>
|
||||
</desc>
|
||||
<req name='acodes'>
|
||||
Pipe-separated list of A-codes you're interested in.
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
Works the same as in the <b>attribute</b> method.
|
||||
</opt>
|
||||
<opt name='fields' default='name'>
|
||||
Works the same as in the <b>attribute</b> method.
|
||||
</opt>
|
||||
<opt name='forward_compatible' default='true'>
|
||||
This has a similar meaning as in the <b>attribute</b> method, but works
|
||||
differently. If set to <b>false</b>, OKAPI will return <b>null</b>s
|
||||
for unknown keys (A-codes). You will still receive an HTTP 200 response
|
||||
though!
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. A-codes you provide will be mapped to dictionary keys,
|
||||
and each value will be an object, as described in the <b>attribute</b>
|
||||
method.</p>
|
||||
</returns>
|
||||
<brief>Retrieve data on multiple attributes at once</brief>
|
||||
<issue-id>269</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the <b>attribute</b> method, but
|
||||
with multiple A-codes instead of only one. Read the docs for
|
||||
the <b>attribute</b> method first!</p>
|
||||
</desc>
|
||||
<req name='acodes'>
|
||||
Pipe-separated list of A-codes you're interested in.
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
Works the same as in the <b>attribute</b> method.
|
||||
</opt>
|
||||
<opt name='fields' default='name'>
|
||||
Works the same as in the <b>attribute</b> method.
|
||||
</opt>
|
||||
<opt name='forward_compatible' default='true'>
|
||||
This has a similar meaning as in the <b>attribute</b> method, but works
|
||||
differently. If set to <b>false</b>, OKAPI will return <b>null</b>s
|
||||
for unknown keys (A-codes). You will still receive an HTTP 200 response
|
||||
though!
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. A-codes you provide will be mapped to dictionary keys,
|
||||
and each value will be an object, as described in the <b>attribute</b>
|
||||
method.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -20,198 +20,202 @@ use \Exception;
|
||||
|
||||
class WebService
|
||||
{
|
||||
private static $shutdown_function_registered = false;
|
||||
private static $files_to_unlink = array();
|
||||
private static $shutdown_function_registered = false;
|
||||
private static $files_to_unlink = array();
|
||||
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cache_codes = $request->get_parameter('cache_codes');
|
||||
if ($cache_codes === null) throw new ParamMissing('cache_codes');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$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!
|
||||
# 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";
|
||||
$images = $request->get_parameter('images');
|
||||
if (!$images) $images = "all";
|
||||
if (!in_array($images, array("none", "all", "spoilers", "nonspoilers")))
|
||||
throw new InvalidParam('images');
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
$images = $request->get_parameter('images');
|
||||
if (!$images) $images = "all";
|
||||
if (!in_array($images, array("none", "all", "spoilers", "nonspoilers")))
|
||||
throw new InvalidParam('images');
|
||||
$location_source = $request->get_parameter('location_source');
|
||||
$location_change_prefix = $request->get_parameter('location_change_prefix');
|
||||
|
||||
# Start creating ZIP archive.
|
||||
# Start creating ZIP archive.
|
||||
|
||||
$tempfilename = Okapi::get_var_dir()."/garmin".time().rand(100000,999999).".zip";
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($tempfilename, ZIPARCHIVE::CREATE) !== true)
|
||||
throw new Exception("ZipArchive class could not create temp file $tempfilename. Check permissions!");
|
||||
$tempfilename = Okapi::get_var_dir()."/garmin".time().rand(100000,999999).".zip";
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($tempfilename, ZIPARCHIVE::CREATE) !== true)
|
||||
throw new Exception("ZipArchive class could not create temp file $tempfilename. Check permissions!");
|
||||
|
||||
# Create basic structure
|
||||
# Create basic structure
|
||||
|
||||
$zip->addEmptyDir("Garmin");
|
||||
$zip->addEmptyDir("Garmin/GPX");
|
||||
$zip->addEmptyDir("Garmin/GeocachePhotos");
|
||||
$zip->addEmptyDir("Garmin");
|
||||
$zip->addEmptyDir("Garmin/GPX");
|
||||
$zip->addEmptyDir("Garmin/GeocachePhotos");
|
||||
|
||||
# Include a GPX file compatible with Garmin devices. It should include all
|
||||
# Geocaching.com (groundspeak:) and Opencaching.com (ox:) extensions. It will
|
||||
# also include image references (actual images will be added as separate files later)
|
||||
# and personal data (if the method was invoked using Level 3 Authentication).
|
||||
# Include a GPX file compatible with Garmin devices. It should include all
|
||||
# Geocaching.com (groundspeak:) and Opencaching.com (ox:) extensions. It will
|
||||
# also include image references (actual images will be added as separate files later)
|
||||
# and personal data (if the method was invoked using Level 3 Authentication).
|
||||
|
||||
$zip->addFromString("Garmin/GPX/opencaching".time().rand(100000,999999).".gpx",
|
||||
OkapiServiceRunner::call('services/caches/formatters/gpx', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array(
|
||||
'cache_codes' => $cache_codes,
|
||||
'langpref' => $langpref,
|
||||
'ns_ground' => 'true',
|
||||
'ns_ox' => 'true',
|
||||
'images' => 'ox:all',
|
||||
'attrs' => 'ox:tags',
|
||||
'trackables' => 'desc:count',
|
||||
'alt_wpts' => 'true',
|
||||
'recommendations' => 'desc:count',
|
||||
'latest_logs' => 'true',
|
||||
'lpc' => 'all',
|
||||
'my_notes' => ($request->token != null) ? "desc:text" : "none"
|
||||
)))->get_body());
|
||||
$zip->addFromString("Garmin/GPX/opencaching".time().rand(100000,999999).".gpx",
|
||||
OkapiServiceRunner::call('services/caches/formatters/gpx', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array(
|
||||
'cache_codes' => $cache_codes,
|
||||
'langpref' => $langpref,
|
||||
'ns_ground' => 'true',
|
||||
'ns_ox' => 'true',
|
||||
'images' => 'ox:all',
|
||||
'attrs' => 'ox:tags',
|
||||
'trackables' => 'desc:count',
|
||||
'alt_wpts' => 'true',
|
||||
'recommendations' => 'desc:count',
|
||||
'latest_logs' => 'true',
|
||||
'lpc' => 'all',
|
||||
'my_notes' => ($request->token != null) ? "desc:text" : "none",
|
||||
'location_source' => $location_source,
|
||||
'location_change_prefix' => $location_change_prefix
|
||||
)))->get_body());
|
||||
|
||||
# Then, include all the images.
|
||||
# Then, include all the images.
|
||||
|
||||
$caches = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('cache_codes' => $cache_codes,
|
||||
'langpref' => $langpref, 'fields' => "images")));
|
||||
if (count($caches) > 50)
|
||||
throw new InvalidParam('cache_codes', "The maximum number of caches allowed to be downloaded with this method is 50.");
|
||||
if ($images != 'none')
|
||||
{
|
||||
$supported_extensions = array('jpg', 'jpeg', 'gif', 'png', 'bmp');
|
||||
foreach ($caches as $cache_code => $dict)
|
||||
{
|
||||
$imgs = $dict['images'];
|
||||
if (count($imgs) == 0)
|
||||
continue;
|
||||
$dir = "Garmin/GeocachePhotos/".$cache_code[strlen($cache_code) - 1];
|
||||
$zip->addEmptyDir($dir); # fails silently if it already exists
|
||||
$dir .= "/".$cache_code[strlen($cache_code) - 2];
|
||||
$zip->addEmptyDir($dir);
|
||||
$dir .= "/".$cache_code;
|
||||
$zip->addEmptyDir($dir);
|
||||
foreach ($imgs as $no => $img)
|
||||
{
|
||||
if ($images == 'spoilers' && (!$img['is_spoiler']))
|
||||
continue;
|
||||
if ($images == 'nonspoilers' && $img['is_spoiler'])
|
||||
continue;
|
||||
$tmp = false;
|
||||
foreach ($supported_extensions as $ext)
|
||||
{
|
||||
if (strtolower(substr($img['url'], strlen($img['url']) - strlen($ext) - 1)) != ".".$ext)
|
||||
{
|
||||
$tmp = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!$tmp)
|
||||
continue; # unsupported file extension
|
||||
$caches = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('cache_codes' => $cache_codes,
|
||||
'langpref' => $langpref, 'fields' => "images")));
|
||||
if (count($caches) > 50)
|
||||
throw new InvalidParam('cache_codes', "The maximum number of caches allowed to be downloaded with this method is 50.");
|
||||
if ($images != 'none')
|
||||
{
|
||||
$supported_extensions = array('jpg', 'jpeg', 'gif', 'png', 'bmp');
|
||||
foreach ($caches as $cache_code => $dict)
|
||||
{
|
||||
$imgs = $dict['images'];
|
||||
if (count($imgs) == 0)
|
||||
continue;
|
||||
$dir = "Garmin/GeocachePhotos/".$cache_code[strlen($cache_code) - 1];
|
||||
$zip->addEmptyDir($dir); # fails silently if it already exists
|
||||
$dir .= "/".$cache_code[strlen($cache_code) - 2];
|
||||
$zip->addEmptyDir($dir);
|
||||
$dir .= "/".$cache_code;
|
||||
$zip->addEmptyDir($dir);
|
||||
foreach ($imgs as $no => $img)
|
||||
{
|
||||
if ($images == 'spoilers' && (!$img['is_spoiler']))
|
||||
continue;
|
||||
if ($images == 'nonspoilers' && $img['is_spoiler'])
|
||||
continue;
|
||||
$tmp = false;
|
||||
foreach ($supported_extensions as $ext)
|
||||
{
|
||||
if (strtolower(substr($img['url'], strlen($img['url']) - strlen($ext) - 1)) != ".".$ext)
|
||||
{
|
||||
$tmp = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!$tmp)
|
||||
continue; # unsupported file extension
|
||||
|
||||
if ($img['is_spoiler']) {
|
||||
$zip->addEmptyDir($dir."/Spoilers");
|
||||
$zippath = $dir."/Spoilers/".$img['unique_caption'].".jpg";
|
||||
} else {
|
||||
$zippath = $dir."/".$img['unique_caption'].".jpg";
|
||||
}
|
||||
if ($img['is_spoiler']) {
|
||||
$zip->addEmptyDir($dir."/Spoilers");
|
||||
$zippath = $dir."/Spoilers/".$img['unique_caption'].".jpg";
|
||||
} else {
|
||||
$zippath = $dir."/".$img['unique_caption'].".jpg";
|
||||
}
|
||||
|
||||
# The safest way would be to use the URL, but that would be painfully slow!
|
||||
# That's why we're trying to access files directly (and fail silently on error).
|
||||
# This was tested on OCPL server only.
|
||||
# The safest way would be to use the URL, but that would be painfully slow!
|
||||
# That's why we're trying to access files directly (and fail silently on error).
|
||||
# This was tested on OCPL server only.
|
||||
|
||||
# Note: Oliver Dietz (oc.de) replied that images with 'local' set to 0 could not
|
||||
# be accessed locally. But all the files have 'local' set to 1 anyway.
|
||||
# Note: Oliver Dietz (oc.de) replied that images with 'local' set to 0 could not
|
||||
# be accessed locally. But all the files have 'local' set to 1 anyway.
|
||||
|
||||
$syspath = Settings::get('IMAGES_DIR')."/".$img['uuid'].".jpg";
|
||||
if (file_exists($syspath))
|
||||
{
|
||||
$file = file_get_contents($syspath);
|
||||
if ($file)
|
||||
$zip->addFromString($zippath, $file);
|
||||
}
|
||||
else
|
||||
{
|
||||
# If file exists, but does not end with ".jpg", we will create
|
||||
# JPEG version of it and store it in the cache.
|
||||
$syspath = Settings::get('IMAGES_DIR')."/".$img['uuid'].".jpg";
|
||||
if (file_exists($syspath))
|
||||
{
|
||||
$file = file_get_contents($syspath);
|
||||
if ($file)
|
||||
$zip->addFromString($zippath, $file);
|
||||
}
|
||||
else
|
||||
{
|
||||
# If file exists, but does not end with ".jpg", we will create
|
||||
# JPEG version of it and store it in the cache.
|
||||
|
||||
$cache_key = "jpg#".$img['uuid'];
|
||||
$jpeg_contents = Cache::get($cache_key);
|
||||
if ($jpeg_contents === null)
|
||||
{
|
||||
foreach ($supported_extensions as $ext)
|
||||
{
|
||||
$syspath_other = Settings::get('IMAGES_DIR')."/".$img['uuid'].".".$ext;
|
||||
if (file_exists($syspath_other))
|
||||
{
|
||||
try
|
||||
{
|
||||
$image = imagecreatefromstring(file_get_contents($syspath_other));
|
||||
ob_start();
|
||||
imagejpeg($image);
|
||||
$jpeg_contents = ob_get_clean();
|
||||
imagedestroy($image);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# GD couldn't parse the file. We will skip it, and cache
|
||||
# the "false" value as the contents. This way, we won't
|
||||
# attempt to parse it during the next 24 hours.
|
||||
$cache_key = "jpg#".$img['uuid'];
|
||||
$jpeg_contents = Cache::get($cache_key);
|
||||
if ($jpeg_contents === null)
|
||||
{
|
||||
foreach ($supported_extensions as $ext)
|
||||
{
|
||||
$syspath_other = Settings::get('IMAGES_DIR')."/".$img['uuid'].".".$ext;
|
||||
if (file_exists($syspath_other))
|
||||
{
|
||||
try
|
||||
{
|
||||
$image = imagecreatefromstring(file_get_contents($syspath_other));
|
||||
ob_start();
|
||||
imagejpeg($image);
|
||||
$jpeg_contents = ob_get_clean();
|
||||
imagedestroy($image);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# GD couldn't parse the file. We will skip it, and cache
|
||||
# the "false" value as the contents. This way, we won't
|
||||
# attempt to parse it during the next 24 hours.
|
||||
|
||||
$jpeg_contents = false;
|
||||
}
|
||||
Cache::set($cache_key, $jpeg_contents, 86400);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($jpeg_contents) # This can be "null" *or* "false"!
|
||||
$zip->addFromString($zippath, $jpeg_contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$jpeg_contents = false;
|
||||
}
|
||||
Cache::set($cache_key, $jpeg_contents, 86400);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($jpeg_contents) # This can be "null" *or* "false"!
|
||||
$zip->addFromString($zippath, $jpeg_contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
$zip->close();
|
||||
|
||||
# The result could be big. Bigger than our memory limit. We will
|
||||
# return an open file stream instead of a string. We also should
|
||||
# set a higher time limit, because downloading this response may
|
||||
# take some time over slow network connections (and I'm not sure
|
||||
# what is the PHP's default way of handling such scenario).
|
||||
# The result could be big. Bigger than our memory limit. We will
|
||||
# return an open file stream instead of a string. We also should
|
||||
# set a higher time limit, because downloading this response may
|
||||
# take some time over slow network connections (and I'm not sure
|
||||
# what is the PHP's default way of handling such scenario).
|
||||
|
||||
set_time_limit(600);
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "application/zip";
|
||||
$response->content_disposition = 'attachment; filename="results.zip"';
|
||||
$response->stream_length = filesize($tempfilename);
|
||||
$response->body = fopen($tempfilename, "rb");
|
||||
$response->allow_gzip = false;
|
||||
self::add_file_to_unlink($tempfilename);
|
||||
return $response;
|
||||
}
|
||||
set_time_limit(600);
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "application/zip";
|
||||
$response->content_disposition = 'attachment; filename="results.zip"';
|
||||
$response->stream_length = filesize($tempfilename);
|
||||
$response->body = fopen($tempfilename, "rb");
|
||||
$response->allow_gzip = false;
|
||||
self::add_file_to_unlink($tempfilename);
|
||||
return $response;
|
||||
}
|
||||
|
||||
private static function add_file_to_unlink($filename)
|
||||
{
|
||||
if (!self::$shutdown_function_registered)
|
||||
register_shutdown_function(array("okapi\\services\\caches\\formatters\\garmin\\WebService", "unlink_temporary_files"));
|
||||
self::$files_to_unlink[] = $filename;
|
||||
}
|
||||
private static function add_file_to_unlink($filename)
|
||||
{
|
||||
if (!self::$shutdown_function_registered)
|
||||
register_shutdown_function(array("okapi\\services\\caches\\formatters\\garmin\\WebService", "unlink_temporary_files"));
|
||||
self::$files_to_unlink[] = $filename;
|
||||
}
|
||||
|
||||
public static function unlink_temporary_files()
|
||||
{
|
||||
foreach (self::$files_to_unlink as $filename)
|
||||
@unlink($filename);
|
||||
self::$files_to_unlink = array();
|
||||
}
|
||||
public static function unlink_temporary_files()
|
||||
{
|
||||
foreach (self::$files_to_unlink as $filename)
|
||||
@unlink($filename);
|
||||
self::$files_to_unlink = array();
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +1,55 @@
|
||||
<xml>
|
||||
<brief>Retrieve ZIP file for Garmin devices</brief>
|
||||
<issue-id>99</issue-id>
|
||||
<desc>
|
||||
<p>Produce a ZIP file with content compatible with Geocaching-enabled Garmin
|
||||
GPS devices. The general idea is, <b>you should <u>extract</u> the contents</b> of the ZIP
|
||||
file directly <b>into the root directory</b> of your Garmin's internal memory storage
|
||||
(currently it doesn't work if you extract the data to the external MicroSD card). The device
|
||||
will then be filled with all the data we are currently able to fill it with.</p>
|
||||
<p>Currently, the ZIP file will contain GPX file and all JPEG images associated
|
||||
with the chosen geocaches. Options for the GPX file are fixed, use the
|
||||
services/caches/formatters/gpx method if
|
||||
you want a custom-tailored GPX file.</p>
|
||||
<p><b>Important note:</b> The contents of the returned ZIP archive may change in the
|
||||
future. You should not parse the contents, nor assume that they have any specific
|
||||
structure.</p>
|
||||
<p><b>Important note:</b> We might be increasing required authentication level for
|
||||
this method to level 2 or 3. You should be prepared for that. Use the highest authentication
|
||||
level you've got. Also, if you want the GPX file to include <b>personal data (like user's notes)</b>,
|
||||
you have to use Level 3 Authentication anyway.</p>
|
||||
<p><b>Note:</b> All non-JPEG images will be skipped. Currently OKAPI does not convert
|
||||
other types of images to JPEG.</p>
|
||||
</desc>
|
||||
<req name='cache_codes'>
|
||||
<p>Pipe-separated list of cache codes which you are interested in.
|
||||
No more than 50 codes are allowed. (This limit is smaller than usual, because
|
||||
we're afraid about the sizes of ZIP files produced.)
|
||||
This CAN be an empty string (it will still result in a valid ZIP file).</p>
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for GPX entities.</p>
|
||||
</opt>
|
||||
<opt name='images' default='all'>
|
||||
<p>One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>none</b> - no images will be included in the result,</li>
|
||||
<li><b>all</b> - all images will be included in the result,</li>
|
||||
<li><b>spoilers</b> - only spoiler images will be included in the result,</li>
|
||||
<li><b>nonspoilers</b> - only non-spoiler images will be included in the result.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<returns>
|
||||
<p>ZIP file. You should extract it's contents directly into the root
|
||||
directory of your Garmin's internal memory storage.</p>
|
||||
</returns>
|
||||
<brief>Retrieve ZIP file for Garmin devices</brief>
|
||||
<issue-id>99</issue-id>
|
||||
<desc>
|
||||
<p>Produce a ZIP file with content compatible with Geocaching-enabled Garmin
|
||||
GPS devices. The general idea is, <b>you should <u>extract</u> the contents</b> of the ZIP
|
||||
file directly <b>into the root directory</b> of your Garmin's internal memory storage
|
||||
(currently it doesn't work if you extract the data to the external MicroSD card). The device
|
||||
will then be filled with all the data we are currently able to fill it with.</p>
|
||||
<p>Currently, the ZIP file will contain GPX file and all JPEG images associated
|
||||
with the chosen geocaches. Options for the GPX file are fixed, use the
|
||||
services/caches/formatters/gpx method if
|
||||
you want a custom-tailored GPX file.</p>
|
||||
<p><b>Important note:</b> The contents of the returned ZIP archive may change in the
|
||||
future. You should not parse the contents, nor assume that they have any specific
|
||||
structure.</p>
|
||||
<p><b>Important note:</b> We might be increasing required authentication level for
|
||||
this method to level 2 or 3. You should be prepared for that. Use the highest authentication
|
||||
level you've got. Also, if you want the GPX file to include <b>personal data (like user's notes)</b>,
|
||||
you have to use Level 3 Authentication anyway.</p>
|
||||
<p><b>Note:</b> All non-JPEG images will be skipped. Currently OKAPI does not convert
|
||||
other types of images to JPEG.</p>
|
||||
</desc>
|
||||
<req name='cache_codes'>
|
||||
<p>Pipe-separated list of cache codes which you are interested in.
|
||||
No more than 50 codes are allowed. (This limit is smaller than usual, because
|
||||
we're afraid about the sizes of ZIP files produced.)
|
||||
This CAN be an empty string (it will still result in a valid ZIP file).</p>
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for GPX entities.</p>
|
||||
</opt>
|
||||
<opt name='images' default='all'>
|
||||
<p>One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>none</b> - no images will be included in the result,</li>
|
||||
<li><b>all</b> - all images will be included in the result,</li>
|
||||
<li><b>spoilers</b> - only spoiler images will be included in the result,</li>
|
||||
<li><b>nonspoilers</b> - only non-spoiler images will be included in the result.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name="location_source" default='default-coords'>
|
||||
Same as in the <a href="%OKAPI:methodargref:services/caches/formatters/gpx#location_source%">
|
||||
services/caches/formatters/gpx</a> method.
|
||||
</opt>
|
||||
<opt name="location_change_prefix" default="#">
|
||||
Same as in the <a href="%OKAPI:methodargref:services/caches/formatters/gpx#location_change_prefix%">
|
||||
services/caches/formatters/gpx</a> method.
|
||||
</opt>
|
||||
<returns>
|
||||
<p>ZIP file. You should extract it's contents directly into the root
|
||||
directory of your Garmin's internal memory storage.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -19,297 +19,383 @@ use okapi\services\attrs\AttrHelper;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
/** Maps OKAPI cache type codes to Geocaching.com GPX cache types. */
|
||||
public static $cache_GPX_types = array(
|
||||
'Traditional' => 'Traditional Cache',
|
||||
'Multi' => 'Multi-Cache',
|
||||
'Quiz' => 'Unknown Cache',
|
||||
'Event' => 'Event Cache',
|
||||
'Virtual' => 'Virtual Cache',
|
||||
'Webcam' => 'Webcam Cache',
|
||||
'Moving' => 'Unknown Cache',
|
||||
'Math/Physics' => 'Unknown Cache',
|
||||
'Drive-In' => 'Traditional Cache',
|
||||
'Own' => 'Unknown Cache',
|
||||
'Other' => 'Unknown Cache'
|
||||
);
|
||||
/** Maps OKAPI cache type codes to Geocaching.com GPX cache types. */
|
||||
public static $cache_GPX_types = array(
|
||||
'Traditional' => 'Traditional Cache',
|
||||
'Multi' => 'Multi-Cache',
|
||||
'Quiz' => 'Unknown Cache',
|
||||
'Event' => 'Event Cache',
|
||||
'Virtual' => 'Virtual Cache',
|
||||
'Webcam' => 'Webcam Cache',
|
||||
'Moving' => 'Unknown Cache',
|
||||
'Math/Physics' => 'Unknown Cache',
|
||||
'Drive-In' => 'Traditional Cache',
|
||||
'Podcast' => 'Unknown Cache',
|
||||
'Own' => 'Unknown Cache',
|
||||
'Other' => 'Unknown Cache'
|
||||
);
|
||||
|
||||
/** Maps OKAPI's 'size2' values to geocaching.com size codes. */
|
||||
public static $cache_GPX_sizes = array(
|
||||
'none' => 'Virtual',
|
||||
'nano' => 'Micro',
|
||||
'micro' => 'Micro',
|
||||
'small' => 'Small',
|
||||
'regular' => 'Regular',
|
||||
'large' => 'Large',
|
||||
'xlarge' => 'Large',
|
||||
'other' => 'Other',
|
||||
);
|
||||
/** Maps OKAPI's 'size2' values to geocaching.com size codes. */
|
||||
public static $cache_GPX_sizes = array(
|
||||
'none' => 'Virtual',
|
||||
'nano' => 'Micro',
|
||||
'micro' => 'Micro',
|
||||
'small' => 'Small',
|
||||
'regular' => 'Regular',
|
||||
'large' => 'Large',
|
||||
'xlarge' => 'Large',
|
||||
'other' => 'Other',
|
||||
);
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$vars = array();
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$vars = array();
|
||||
|
||||
# Validating arguments. We will also assign some of them to the
|
||||
# $vars variable which we will use later in the GPS template.
|
||||
# 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');
|
||||
$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!
|
||||
# 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";
|
||||
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.");
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
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'");
|
||||
}
|
||||
}
|
||||
}
|
||||
$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;
|
||||
$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'");
|
||||
}
|
||||
}
|
||||
$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;
|
||||
$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('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;
|
||||
$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
|
||||
$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');
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
|
||||
# Which fields of the services/caches/geocaches method do we need?
|
||||
# location_source (part 1 of 2)
|
||||
|
||||
$fields = 'code|name|location|date_created|url|type|status|size|size2|oxsize'.
|
||||
'|difficulty|terrain|description|hint2|rating|owner|url|internal_id'.
|
||||
'|protection_areas';
|
||||
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')
|
||||
$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";
|
||||
$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.'\'');
|
||||
}
|
||||
|
||||
$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'
|
||||
)
|
||||
)
|
||||
);
|
||||
# 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'.");
|
||||
}
|
||||
|
||||
# Get all the other data need.
|
||||
# Which fields of the services/caches/geocaches method do we 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;
|
||||
$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";
|
||||
|
||||
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['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'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$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'
|
||||
)
|
||||
)
|
||||
);
|
||||
# Get rid of invalid cache references.
|
||||
|
||||
# prepare GS attribute data
|
||||
$valid = array();
|
||||
foreach ($vars['caches'] as $key => &$ref) {
|
||||
if ($ref !== null) {
|
||||
$valid[$key] = &$ref;
|
||||
}
|
||||
}
|
||||
$vars['caches'] = &$valid;
|
||||
unset($valid);
|
||||
|
||||
$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.
|
||||
# Get all the other data need.
|
||||
|
||||
$ocde_attrnames = Db::select_group_by('id',"
|
||||
select id, name
|
||||
from cache_attrib
|
||||
");
|
||||
$attr_dict = AttrHelper::get_attrdict();
|
||||
}
|
||||
$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;
|
||||
|
||||
foreach ($vars['caches'] as &$cache)
|
||||
{
|
||||
$cache['gc_attrs'] = array();
|
||||
foreach ($cache['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.
|
||||
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. */
|
||||
|
||||
$cache['gc_attrs'][$gc['id']] = $gc;
|
||||
$has_gc_equivs = true;
|
||||
}
|
||||
if (!$has_gc_equivs && $vars['gc_ocde_attrs'])
|
||||
{
|
||||
# Generate an OCDE pseudo-GS attribute;
|
||||
# see http://code.google.com/p/opencaching-api/issues/detail?id=190 and
|
||||
# http://code.google.com/p/opencaching-api/issues/detail?id=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.
|
||||
$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'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$internal_id = $attr_dict[$acode]['internal_id'];
|
||||
$cache['gc_attrs'][100 + $internal_id] = array(
|
||||
'inc' => 1,
|
||||
'name' => $ocde_attrnames[$internal_id][0]['name'],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# prepare GS attribute data
|
||||
|
||||
/* 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. */
|
||||
$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.
|
||||
|
||||
$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("
|
||||
select uuid, user_id
|
||||
from user
|
||||
where uuid in ('".implode("','", array_map('mysql_real_escape_string', array_keys($dict)))."')
|
||||
");
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$dict[$row['uuid']] = $row['user_id'];
|
||||
$vars['user_uuid_to_internal_id'] = &$dict;
|
||||
unset($dict);
|
||||
$ocde_attrnames = Db::select_group_by('id',"
|
||||
select id, name
|
||||
from cache_attrib
|
||||
");
|
||||
$attr_dict = AttrHelper::get_attrdict();
|
||||
}
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "application/gpx; charset=utf-8";
|
||||
$response->content_disposition = 'attachment; filename="results.gpx"';
|
||||
ob_start();
|
||||
Okapi::gettext_domain_init(explode("|", $langpref)); # Consumer gets properly localized GPX file.
|
||||
include 'gpxfile.tpl.php';
|
||||
Okapi::gettext_domain_restore();
|
||||
$response->body = ob_get_clean();
|
||||
return $response;
|
||||
}
|
||||
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 http://code.google.com/p/opencaching-api/issues/detail?id=190 and
|
||||
# http://code.google.com/p/opencaching-api/issues/detail?id=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("
|
||||
select uuid, user_id
|
||||
from user
|
||||
where uuid in ('".implode("','", array_map('mysql_real_escape_string', array_keys($dict)))."')
|
||||
");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "application/gpx; charset=utf-8";
|
||||
$response->content_disposition = 'attachment; filename="results.gpx"';
|
||||
ob_start();
|
||||
Okapi::gettext_domain_init(explode("|", $langpref)); # Consumer gets properly localized GPX file.
|
||||
include 'gpxfile.tpl.php';
|
||||
Okapi::gettext_domain_restore();
|
||||
$response->body = ob_get_clean();
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -1,198 +1,257 @@
|
||||
<xml>
|
||||
<brief>Retrieve geocaches in GPX format</brief>
|
||||
<issue-id>40</issue-id>
|
||||
<desc>
|
||||
<p>Produces a standards-compliant Geocaching GPX file.</p>
|
||||
<p>Unlike the services/caches/geocaches method responses, GPX files cannot
|
||||
contain names and descriptions in separate multiple languages. This method
|
||||
will attempt to choose the best language based on your preference
|
||||
(see <b>langpref</b> argument).</p>
|
||||
<p>Remember that a full-blown GPX file is much larger than a basic one.
|
||||
This method can produce many various types of GPX files. The simplest list of
|
||||
waypoints takes ~50 times less space than the same list with cache descriptions
|
||||
and log entries included.</p>
|
||||
<p>Note, that GPX files may contain <a href='%OKAPI:docurl:html%'>unvalidated
|
||||
HTML</a>.</p>
|
||||
</desc>
|
||||
<req name='cache_codes'>
|
||||
<p>Pipe-separated list of cache codes which you are interested in.
|
||||
No more than 500 codes are allowed. This CAN be an empty string (it will
|
||||
result in an empty, but valid, GPX file). All invalid cache codes will
|
||||
be skipped without any notice!</p>
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for GPX entities.</p>
|
||||
</opt>
|
||||
<opt name='ns_ground' default='false'>
|
||||
Boolean. If <b>true</b> then response will include
|
||||
<a href='http://www.groundspeak.com/cache/1/0/1/cache.xsd'>Groundspeak's
|
||||
GPX extension</a>. This namespace declares an extra <cache> element
|
||||
used by <a href='http://www.geocaching.com/'>geocaching.com</a> and <b>many others</b>.
|
||||
This namespace was initially associatied with geocaching.com, but now seems to
|
||||
be used in every geocaching GPX file. You probably want to have it.
|
||||
</opt>
|
||||
<opt name='ns_gsak' default='false'>
|
||||
<p>Boolean. If <b>true</b> then response will include
|
||||
<a href='http://www.gsak.net/xmlv1/5/gsak.xsd'>GSAK GPX extension</a>.
|
||||
This namespace declares an extra <wptExtension> element,
|
||||
which allows including "waypoint inheritance" information (parent-child relations).
|
||||
This in turn allows us to include "alternate waypoints" in the response.</p>
|
||||
<p>We know of <b>at least</b> <a href='http://www.gsak.net/'>one tool</a> that
|
||||
makes use of this.</p>
|
||||
</opt>
|
||||
<opt name='ns_ox' default='false'>
|
||||
Boolean. If <b>true</b> then response will include Garmin's
|
||||
<a href='http://www.opencaching.com/xmlschemas/opencaching/1/0/opencaching.xsd'>OpenCaching.com
|
||||
GPX extension</a>. This namespace declares an extra <opencaching> element
|
||||
used by <a href='http://www.opencaching.com/'>Garmin's Opencaching.com</a>.
|
||||
The element includes information on cache difficulty, ratings, tags and images.
|
||||
It is used within Garmin's Geocaching-enabled handheld GPS devices.
|
||||
</opt>
|
||||
<opt name='images' default='descrefs:nonspoilers'>
|
||||
<p>Which images to include (and how to include them). One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>none</b> - no images will be included,</li>
|
||||
<li><b>descrefs:thumblinks</b> - all images will be included as "thumbnail"
|
||||
<img> references at the end of each cache description, with a
|
||||
replacement image used for spoilers; the thumbnails are linked to the
|
||||
large images,</li>
|
||||
<li><b>descrefs:nonspoilers</b> - all non-spoiler images will be included
|
||||
as <img> references at the end of each cache description,</li>
|
||||
<li><b>descrefs:all</b> - all images will be included (including spoilers)
|
||||
as <img> references at the end of each cache description,</li>
|
||||
<li><b>ox:all</b> - all images will be included (including spoilers)
|
||||
as Garmin's <ox:image> references.</li>
|
||||
</ul>
|
||||
<p>Note: When using "descrefs:" mode, remember to set <b>ns_ground</b> to <b>true</b>.
|
||||
The default value is "descrefs:nonspoilers" for compatibilty reasons, but for
|
||||
most applications "descrefs:thumblinks" will be the better choice.</p>
|
||||
<p>Note: When using "ox:" mode, remember to set <b>ns_ox</b> to <b>true</b>. You must also
|
||||
include JPEG files along the GPX for this to work properly - see
|
||||
services/caches/formatters/garmin for more information.</p>
|
||||
<p>In the future, more generic ways of including images in GPX files may emerge.</p>
|
||||
</opt>
|
||||
<opt name='attrs' default='desc:text'>
|
||||
<p>This argument controls whether cache attributes are included and how they are included.
|
||||
Pipe-separated list consisting of any set of the following values:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>desc:text</b> - attributes will be listed (in plain-text) within
|
||||
the cache description (<b>ns_ground</b> has to be <b>true</b>),</li>
|
||||
<li><b>ox:tags</b> - attributes will be listed as Garmin's <i>ox:tag</i>
|
||||
elements (<b>ns_ox</b> has to be <b>true</b>),</li>
|
||||
<li>
|
||||
<p><b>gc:attrs</b> - attributes will be listed as Groundspeak's
|
||||
<i>groundspeak:attribute</i> elements (<b>ns_ground</b> has to be <b>true</b>),
|
||||
compatible with Geocaching.com (see the list
|
||||
<a href='http://www.geocaching.com/about/icons.aspx'>here</a>).</p>
|
||||
<p>Note that most Opencaching attributes don't have Geocaching.com counterparts.
|
||||
Such attributes cannot be included as gc:attrs and will be ignored.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>gc_ocde:attrs</b> - attributes will be listed as Groundspeak's
|
||||
<i>groundspeak:attribute</i> elements (<b>ns_ground</b> has to be <b>true</b>).
|
||||
Opencaching attributes which have no Geocaching.com counterparts will be
|
||||
included according to an Opencaching.DE convention, using "makeshift IDs"
|
||||
which may change in the future.</p>
|
||||
<p>Note that this option is supported only by some OC sites. Other sites will
|
||||
handle <b>gc_ocde:attrs</b> in the same way as <b>gc:attrs</b>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>If you don't want any attributes to be included, you must set the <b>attrs</b>
|
||||
parameter to <b>none</b>. Using an empty string won't work this way - it will
|
||||
trigger the default (<b>desc:text</b>) to be selected, for backward-compatibility.</p>
|
||||
</opt>
|
||||
<opt name='protection_areas' default='desc:auto'>
|
||||
<p>This argument controls whether protection area information is included and how
|
||||
it is included.</p>
|
||||
<ul>
|
||||
<li><b>desc:text</b> - if the cache (probably) is located within one or more
|
||||
protection areas, e.g. a nature reserve, a list of the protection areas will
|
||||
be included in the cache description.</li>
|
||||
<li><b>desc:auto</b> - protection area information may be included in the
|
||||
cache description, depending on the installation.</li>
|
||||
<li><b>none</b> - no protection area information will be included in the
|
||||
GPX data.</li>
|
||||
</ul>
|
||||
<p>Note that information on protection areas may be incomplete or outdated
|
||||
or completely missing on some installations.</p>
|
||||
</opt>
|
||||
<opt name='trackables' default='none'>
|
||||
<p>This argument controls whether information on trackables is included and how it is included.
|
||||
One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>none</b> - no trackables-data will be included,</li>
|
||||
<li><b>desc:list</b> - trackables will be listed (in plain-text) within the cache description,</li>
|
||||
<li><b>desc:count</b> - total number of trackables will be included (in plain-text) within the cache description.</li>
|
||||
</ul>
|
||||
<p>Note: When using "desc:" mode, remember to set <b>ns_ground</b> to <b>true</b>.</p>
|
||||
</opt>
|
||||
<opt name='recommendations' default='none'>
|
||||
<p>This argument controls whether information on recommendations is included and how it is included.
|
||||
One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>none</b> - no recommendations-info will be included,</li>
|
||||
<li><b>desc:count</b> - number of recommendations (and founds) will be included
|
||||
(in plain-text) within the cache description.</li>
|
||||
</ul>
|
||||
<p>Note: When using "desc:" mode, remember to set <b>ns_ground</b> to <b>true</b>.</p>
|
||||
</opt>
|
||||
<opt name='my_notes' default='none'>
|
||||
<p>Allows you to include personal user's notes on each cache. This parameter
|
||||
takes either <b>none</b> (default value), or pipe separeted list of the
|
||||
following values:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>desc:text</b> - include personal notes as part of the cache
|
||||
description.</li>
|
||||
|
||||
<li>
|
||||
<p><b>gc:personal_note</b> - include personal notes as
|
||||
<groundspeak:personal_note> element (under
|
||||
<groundspeak:cache> element).</p>
|
||||
|
||||
<p><b>Warning:</b> This element is not a part of
|
||||
<i>http://www.groundspeak.com/cache/1/0/1</i> groundspeak schema, but it
|
||||
is a <i>http://www.groundspeak.com/cache/1/0/2</i> schema element. Using
|
||||
this option will generate formally invalid XML file.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Note: You need to use Level 3 Authentication in order to set it to anything else than "none".</p>
|
||||
</opt>
|
||||
<opt name='latest_logs' default='false'>
|
||||
<p>Boolean. If <b>true</b> then response will include a couple of
|
||||
latest log entries for this cache (see also the <b>lpc</b> argument).</p>
|
||||
<p>You <b>must</b> set <b>ns_ground</b> argument to <b>true</b> if you want to use this.</p>
|
||||
</opt>
|
||||
<opt name='lpc' default='10'>
|
||||
Log-entries per cache - the number of log entries included in each returned cache.
|
||||
This should be an integer or a special "all" value. Please note, that the <b>ns_ground</b>
|
||||
and <b>latest_logs</b> arguments must be set to <b>true</b> in order for the logs to be included.
|
||||
</opt>
|
||||
<opt name='alt_wpts' default='false'>
|
||||
<p>Boolean. If <b>true</b> then we will include additional (alternate) waypoints in the response.
|
||||
These are all places associated with the cache.</p>
|
||||
<p>Combine this with <b>ns_gsak</b> if you want the result to include additional references between
|
||||
waypoints and their geocaches. Please note that not many applications are currently able to
|
||||
properly understand GSAK metadata.</p>
|
||||
</opt>
|
||||
<opt name='mark_found' default='false'>
|
||||
<p>Boolean. If <b>true</b> then all caches which are already found, will be marked appropriately
|
||||
(i.e. with an "found cache" symbol).</p>
|
||||
<p>This field requires you to use the <b>user_uuid</b> parameter (or Level 3 Authentication).</p>
|
||||
</opt>
|
||||
<opt name="user_uuid">
|
||||
<p>User'd ID. Required to mark found caches using <b>Level 1</b> Authentication.</p>
|
||||
<p>If you use <b>Level 3</b> Authentication, you shouldn't use this parameter. Or, to be exact:</p>
|
||||
<ul>
|
||||
<li><b>user_uuid</b> will be extracted from the Access Token you use. You don't have to provide it.</li>
|
||||
<li>If you provide <b>user_uuid</b>, then it HAS TO match your Access Token. If it doesn't, OKAPI
|
||||
will respond with HTTP 400 error.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<returns>
|
||||
<p>GPX file. All invalid cache codes will be skipped without any notice!</p>
|
||||
</returns>
|
||||
<brief>Retrieve geocaches in GPX format</brief>
|
||||
<issue-id>40</issue-id>
|
||||
<desc>
|
||||
<p>Produces a standards-compliant Geocaching GPX file.</p>
|
||||
<p>Unlike the services/caches/geocaches method responses, GPX files cannot
|
||||
contain names and descriptions in separate multiple languages. This method
|
||||
will attempt to choose the best language based on your preference
|
||||
(see <b>langpref</b> argument).</p>
|
||||
<p>Remember that a full-blown GPX file is much larger than a basic one.
|
||||
This method can produce many various types of GPX files. The simplest list of
|
||||
waypoints takes ~50 times less space than the same list with cache descriptions
|
||||
and log entries included.</p>
|
||||
<p>Note, that GPX files may contain <a href='%OKAPI:docurl:html%'>unvalidated
|
||||
HTML</a>.</p>
|
||||
</desc>
|
||||
<req name='cache_codes'>
|
||||
<p>Pipe-separated list of cache codes which you are interested in.
|
||||
No more than 500 codes are allowed. This CAN be an empty string (it will
|
||||
result in an empty, but valid, GPX file). All invalid cache codes will
|
||||
be skipped without any notice!</p>
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for GPX entities.</p>
|
||||
</opt>
|
||||
<opt name='ns_ground' default='false'>
|
||||
Boolean. If <b>true</b> then response will include
|
||||
<a href='http://www.groundspeak.com/cache/1/0/1/cache.xsd'>Groundspeak's
|
||||
GPX extension</a>. This namespace declares an extra <cache> element
|
||||
used by <a href='http://www.geocaching.com/'>geocaching.com</a> and <b>many others</b>.
|
||||
This namespace was initially associatied with geocaching.com, but now seems to
|
||||
be used in every geocaching GPX file. You probably want to have it.
|
||||
</opt>
|
||||
<opt name='ns_gsak' default='false'>
|
||||
<p>Boolean. If <b>true</b> then response will include
|
||||
<a href='http://www.gsak.net/xmlv1/5/gsak.xsd'>GSAK GPX extension</a>.
|
||||
This namespace declares an extra <wptExtension> element,
|
||||
which allows including "waypoint inheritance" information (parent-child relations).
|
||||
This in turn allows us to include "alternate waypoints" in the response.</p>
|
||||
<p>We know of <b>at least</b> <a href='http://www.gsak.net/'>one tool</a> that
|
||||
makes use of this.</p>
|
||||
</opt>
|
||||
<opt name='ns_ox' default='false'>
|
||||
Boolean. If <b>true</b> then response will include Garmin's
|
||||
<a href='http://www.opencaching.com/xmlschemas/opencaching/1/0/opencaching.xsd'>OpenCaching.com
|
||||
GPX extension</a>. This namespace declares an extra <opencaching> element
|
||||
used by <a href='http://www.opencaching.com/'>Garmin's Opencaching.com</a>.
|
||||
The element includes information on cache difficulty, ratings, tags and images.
|
||||
It is used within Garmin's Geocaching-enabled handheld GPS devices.
|
||||
</opt>
|
||||
<opt name='images' default='descrefs:nonspoilers'>
|
||||
<p>Which images to include (and how to include them). One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>none</b> - no images will be included,</li>
|
||||
<li><b>descrefs:thumblinks</b> - all images will be included as "thumbnail"
|
||||
<img> references at the end of each cache description, with a
|
||||
replacement image used for spoilers; the thumbnails are linked to the
|
||||
large images,</li>
|
||||
<li><b>descrefs:nonspoilers</b> - all non-spoiler images will be included
|
||||
as <img> references at the end of each cache description,</li>
|
||||
<li><b>descrefs:all</b> - all images will be included (including spoilers)
|
||||
as <img> references at the end of each cache description,</li>
|
||||
<li><b>ox:all</b> - all images will be included (including spoilers)
|
||||
as Garmin's <ox:image> references.</li>
|
||||
</ul>
|
||||
<p>Note: When using "descrefs:" mode, remember to set <b>ns_ground</b> to <b>true</b>.
|
||||
The default value is "descrefs:nonspoilers" for compatibilty reasons, but for
|
||||
most applications "descrefs:thumblinks" will be the better choice.</p>
|
||||
<p>Note: When using "ox:" mode, remember to set <b>ns_ox</b> to <b>true</b>. You must also
|
||||
include JPEG files along the GPX for this to work properly - see
|
||||
services/caches/formatters/garmin for more information.</p>
|
||||
<p>In the future, more generic ways of including images in GPX files may emerge.</p>
|
||||
</opt>
|
||||
<opt name='attrs' default='desc:text'>
|
||||
<p>This argument controls whether cache attributes are included and how they are included.
|
||||
Pipe-separated list consisting of any set of the following values:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>desc:text</b> - attributes will be listed (in plain-text) within
|
||||
the cache description (<b>ns_ground</b> has to be <b>true</b>),</li>
|
||||
<li><b>ox:tags</b> - attributes will be listed as Garmin's <i>ox:tag</i>
|
||||
elements (<b>ns_ox</b> has to be <b>true</b>),</li>
|
||||
<li>
|
||||
<p><b>gc:attrs</b> - attributes will be listed as Groundspeak's
|
||||
<i>groundspeak:attribute</i> elements (<b>ns_ground</b> has to be <b>true</b>),
|
||||
compatible with Geocaching.com (see the list
|
||||
<a href='http://www.geocaching.com/about/icons.aspx'>here</a>).</p>
|
||||
<p>Note that most Opencaching attributes don't have Geocaching.com counterparts.
|
||||
Such attributes cannot be included as gc:attrs and will be ignored.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>gc_ocde:attrs</b> - attributes will be listed as Groundspeak's
|
||||
<i>groundspeak:attribute</i> elements (<b>ns_ground</b> has to be <b>true</b>).
|
||||
Opencaching attributes which have no Geocaching.com counterparts will be
|
||||
included according to an Opencaching.DE convention, using "makeshift IDs"
|
||||
which may change in the future.</p>
|
||||
<p>Note that this option is supported only by some OC sites. Other sites will
|
||||
handle <b>gc_ocde:attrs</b> in the same way as <b>gc:attrs</b>.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>If you don't want any attributes to be included, you must set the <b>attrs</b>
|
||||
parameter to <b>none</b>. Using an empty string won't work this way - it will
|
||||
trigger the default (<b>desc:text</b>) to be selected, for backward-compatibility.</p>
|
||||
</opt>
|
||||
<opt name='protection_areas' default='desc:auto'>
|
||||
<p>This argument controls whether protection area information is included and how
|
||||
it is included.</p>
|
||||
<ul>
|
||||
<li><b>desc:text</b> - if the cache (probably) is located within one or more
|
||||
protection areas, e.g. a nature reserve, a list of the protection areas will
|
||||
be included in the cache description.</li>
|
||||
<li><b>desc:auto</b> - protection area information may be included in the
|
||||
cache description, depending on the installation.</li>
|
||||
<li><b>none</b> - no protection area information will be included in the
|
||||
GPX data.</li>
|
||||
</ul>
|
||||
<p>Note that information on protection areas may be incomplete or outdated
|
||||
or completely missing on some installations.</p>
|
||||
</opt>
|
||||
<opt name='trackables' default='none'>
|
||||
<p>This argument controls whether information on trackables is included and how it is included.
|
||||
One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>none</b> - no trackables-data will be included,</li>
|
||||
<li><b>desc:list</b> - trackables will be listed (in plain-text) within the cache description,</li>
|
||||
<li><b>desc:count</b> - total number of trackables will be included (in plain-text) within the cache description.</li>
|
||||
</ul>
|
||||
<p>Note: When using "desc:" mode, remember to set <b>ns_ground</b> to <b>true</b>.</p>
|
||||
</opt>
|
||||
<opt name='recommendations' default='none'>
|
||||
<p>This argument controls whether information on recommendations is included and how it is included.
|
||||
One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>none</b> - no recommendations-info will be included,</li>
|
||||
<li><b>desc:count</b> - number of recommendations (and founds) will be included
|
||||
(in plain-text) within the cache description.</li>
|
||||
</ul>
|
||||
<p>Note: When using "desc:" mode, remember to set <b>ns_ground</b> to <b>true</b>.</p>
|
||||
</opt>
|
||||
<opt name='my_notes' default='none'>
|
||||
<p>Allows you to include personal user's notes on each cache. This parameter
|
||||
takes either <b>none</b> (default value), or pipe separeted list of the
|
||||
following values:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>desc:text</b> - include personal notes as part of the cache
|
||||
description.</li>
|
||||
|
||||
<li>
|
||||
<p><b>gc:personal_note</b> - include personal notes as
|
||||
<groundspeak:personal_note> element (under
|
||||
<groundspeak:cache> element).</p>
|
||||
|
||||
<p><b>Warning:</b> This element is not a part of
|
||||
<i>http://www.groundspeak.com/cache/1/0/1</i> groundspeak schema, but it
|
||||
is a <i>http://www.groundspeak.com/cache/1/0/2</i> schema element. Using
|
||||
this option will generate formally invalid XML file.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Note: You need to use Level 3 Authentication in order to set it to anything else than "none".</p>
|
||||
</opt>
|
||||
<opt name='latest_logs' default='false'>
|
||||
<p>Boolean. If <b>true</b> then response will include a couple of
|
||||
latest log entries for this cache (see also the <b>lpc</b> argument).</p>
|
||||
<p>You <b>must</b> set <b>ns_ground</b> argument to <b>true</b> if you want to use this.</p>
|
||||
</opt>
|
||||
<opt name='lpc' default='10'>
|
||||
Log-entries per cache - the number of log entries included in each returned cache.
|
||||
This should be an integer or a special "all" value. Please note, that the <b>ns_ground</b>
|
||||
and <b>latest_logs</b> arguments must be set to <b>true</b> in order for the logs to be included.
|
||||
</opt>
|
||||
<opt name='alt_wpts' default='false'>
|
||||
<p>Boolean. If <b>true</b> then we will include additional (alternate) waypoints in the response.
|
||||
These are all places associated with the cache.</p>
|
||||
<p>Combine this with <b>ns_gsak</b> if you want the result to include additional references between
|
||||
waypoints and their geocaches. Please note that not many applications are currently able to
|
||||
properly understand GSAK metadata.</p>
|
||||
</opt>
|
||||
<opt name='mark_found' default='false'>
|
||||
<p>Boolean. If <b>true</b> then all caches which are already found, will be marked appropriately
|
||||
(i.e. with an "found cache" symbol).</p>
|
||||
<p>This field requires you to use the <b>user_uuid</b> parameter (or Level 3 Authentication).</p>
|
||||
</opt>
|
||||
<opt name="user_uuid">
|
||||
<p>User'd ID. Required to mark found caches using <b>Level 1</b> Authentication.</p>
|
||||
<p>If you use <b>Level 3</b> Authentication, you shouldn't use this parameter. Or, to be exact:</p>
|
||||
<ul>
|
||||
<li><b>user_uuid</b> will be extracted from the Access Token you use. You don't have to provide it.</li>
|
||||
<li>If you provide <b>user_uuid</b>, then it HAS TO match your Access Token. If it doesn't, OKAPI
|
||||
will respond with HTTP 400 error.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name="location_source" default='default-coords'>
|
||||
<p>If you supply a value, then it must be prefixed with <i>alt_wpt:</i>,
|
||||
and should match one of alternate waypoint types documented in the
|
||||
<a href="%OKAPI:methodretref:services/caches/geocache#alt_wpts%">alt_wpts</a>
|
||||
field returned by <a href="%OKAPI:methodref:services/caches/geocache%">services/caches/geocache</a>
|
||||
method. If the type doesn't match, it will be ignored.</p>
|
||||
|
||||
<p>By default, the <b>lat</b> and <b>lon</b> attributes of the <b><wpt></b> element
|
||||
will return the default coordinates of the cache, as supplied by the owner of the cache.
|
||||
This option allows you to replace these coordinates with other set of coordinates, loaded
|
||||
from the <b>alt_wpts</b> field mentioned above.</p>
|
||||
|
||||
<p>This may have some advantages in some scenarios. For example, if your user
|
||||
is driving a car, he might be more interested in the coordinates of the
|
||||
nearest suitable parking spot than in the coordinates of the geocache itself.
|
||||
If you set <b>location_source</b> to <b>alt_wpt:parking</b> then you'll be
|
||||
pre-fetching parking locations (if provided) without the need of loading all
|
||||
other <b>alternate waypoints</b> in your requests.</p>
|
||||
|
||||
<p>Other use case: setting this to <b>alt_wpt:user-coords</b> allows
|
||||
personalized results in some OC installations.</p>
|
||||
|
||||
<ul>
|
||||
<li>If the type provided doesn't match any alternate waypoints, the default
|
||||
coordinates of the geocache will be used.</li>
|
||||
|
||||
<li>
|
||||
<p>If the type matches exactly one alternate waypoint, then:</p>
|
||||
|
||||
<ul>
|
||||
<li>The <b>lat</b> and <b>lon</b> attributes of the "primary"
|
||||
<b><wpt></b> element will be replaced with the location of
|
||||
the matched alternate waypoint,</li>
|
||||
|
||||
<li>The name of the geocache will be prefixed with the value suppiled in
|
||||
<b><a href="%OKAPI:methodargref:#location_change_prefix%">location_change_prefix</a></b>
|
||||
parameter,</li>
|
||||
|
||||
<li>The desription of the waypoint will be included in the
|
||||
header of the cache description,</li>
|
||||
|
||||
<li>The matched alternate waypoint will be removed from the list
|
||||
of alternate waypoins (in order to avoid duplicate locations),</li>
|
||||
|
||||
<li>Extra alternate waypoint will be created, with the original
|
||||
location of the geocache.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>If the type provided matches multiple alternate waypoints, then
|
||||
the first one will be chosen.</li>
|
||||
</ul>
|
||||
|
||||
</opt>
|
||||
<opt name="location_change_prefix" default="#">
|
||||
<p>Prefix to be added to the geocache name, in case its location has been changed due to
|
||||
the <b><a href="%OKAPI:methodargref:#location_source%">location_source</a></b> parameter
|
||||
matching any of the alternate waypoint.</p>
|
||||
</opt>
|
||||
<returns>
|
||||
<p>GPX file. All invalid cache codes will be skipped without any notice!</p>
|
||||
</returns>
|
||||
</xml>
|
@ -16,187 +16,192 @@ http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/ca
|
||||
http://geocaching.com.au/geocache/1 http://geocaching.com.au/geocache/1/geocache.xsd
|
||||
http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
">
|
||||
<name><?= $vars['installation']['site_name'] ?> Geocache Search Results</name>
|
||||
<desc><?= $vars['installation']['site_name'] ?> Geocache Search Results, downloaded via OKAPI - <?= $vars['installation']['okapi_base_url'] . ($vars['alt_wpts'] && $vars['ns_gsak'] ? ' (HasChildren)' : '') ?></desc>
|
||||
<author><?= $vars['installation']['site_name'] ?></author>
|
||||
<url><?= $vars['installation']['site_url'] ?></url>
|
||||
<urlname><?= $vars['installation']['site_name'] ?></urlname>
|
||||
<time><?= date('c') ?></time>
|
||||
<? foreach ($vars['caches'] as $c) { ?>
|
||||
<? if ($c == null) continue; /* This happens when there is an invalid code in cache_codes */ ?>
|
||||
<? list($lat, $lon) = explode("|", $c['location']); ?>
|
||||
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
||||
<time><?= $c['date_created'] ?></time>
|
||||
<name><?= $c['code'] ?></name>
|
||||
<desc><?= Okapi::xmlescape($c['name']) ?> <?= _("hidden by") ?> <?= Okapi::xmlescape($c['owner']['username']) ?> :: <?= ucfirst($c['type']) ?> Cache (<?= $c['difficulty'] ?>/<?= $c['terrain'] ?><? if ($c['size'] !== null) { echo "/".$c['size']; } else { echo "/X"; } ?>/<?= $c['rating'] ?>)</desc>
|
||||
<url><?= $c['url'] ?></url>
|
||||
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
||||
<sym><?= ($vars['mark_found'] && $c['is_found']) ? "Geocache Found" : "Geocache" ?></sym>
|
||||
<type>Geocache|<?= $vars['cache_GPX_types'][$c['type']] ?></type>
|
||||
<? if ($vars['ns_ground']) { /* Does user want us to include Groundspeak's <cache> element? */ ?>
|
||||
<groundspeak:cache archived="<?= ($c['status'] == 'Archived') ? "True" : "False" ?>" available="<?= ($c['status'] == 'Available') ? "True" : "False" ?>" id="<?= $c['internal_id'] ?>" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0/1">
|
||||
<groundspeak:name><?= Okapi::xmlescape($c['name']) ?></groundspeak:name>
|
||||
<groundspeak:placed_by><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:placed_by>
|
||||
<groundspeak:owner id="<?= $vars['user_uuid_to_internal_id'][$c['owner']['uuid']] ?>"><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:owner>
|
||||
<groundspeak:type><?= $vars['cache_GPX_types'][$c['type']] ?></groundspeak:type>
|
||||
<groundspeak:container><?= $vars['cache_GPX_sizes'][$c['size2']] ?></groundspeak:container>
|
||||
<? if ($vars['gc_attrs'] || $vars['gc_ocde_attrs']) { /* Does user want us to include groundspeak:attributes? */ ?>
|
||||
<groundspeak:attributes>
|
||||
<?
|
||||
foreach ($c['gc_attrs'] as $gc_id => $gc_attr) {
|
||||
print "<groundspeak:attribute id=\"".$gc_id."\" ";
|
||||
print "inc=\"".$gc_attr['inc']."\">";
|
||||
print Okapi::xmlescape($gc_attr['name']);
|
||||
print "</groundspeak:attribute>";
|
||||
}
|
||||
?>
|
||||
</groundspeak:attributes>
|
||||
<? } ?>
|
||||
<groundspeak:difficulty><?= $c['difficulty'] ?></groundspeak:difficulty>
|
||||
<groundspeak:terrain><?= $c['terrain'] ?></groundspeak:terrain>
|
||||
<groundspeak:long_description html="True">
|
||||
<p>
|
||||
<a href="<?= $c['url'] ?>"><?= Okapi::xmlescape($c['name']) ?></a>
|
||||
<?= _("hidden by") ?> <a href='<?= $c['owner']['profile_url'] ?>'><?= Okapi::xmlescape($c['owner']['username']) ?></a><br/>
|
||||
<? if ($vars['recommendations'] == 'desc:count') { /* Does user want us to include recommendations count? */ ?>
|
||||
<?= sprintf(ngettext("%d recommendation", "%d recommendations", $c['recommendations']), $c['recommendations']) ?>
|
||||
(<?= sprintf(ngettext("found %d time", "found %d times", $c['founds']), $c['founds']) ?>).
|
||||
<? } ?>
|
||||
<? if ($vars['trackables'] == 'desc:count') { /* Does user want us to include trackables count? */ ?>
|
||||
<?= sprintf(ngettext("%d trackable", "%d trackables", $c['trackables_count']), $c['trackables_count']) ?>.
|
||||
<? } ?>
|
||||
</p>
|
||||
<? if ((in_array('desc:text', $vars['my_notes'])) && ($c['my_notes'] != null)) { /* Does user want us to include personal notes? */ ?>
|
||||
<p><b><?= _("Personal notes") ?>:</b><br><?= Okapi::xmlescape(nl2br($c['my_notes'])) ?></p>
|
||||
<? } ?>
|
||||
<name><?= $vars['installation']['site_name'] ?> Geocache Search Results</name>
|
||||
<desc><?= $vars['installation']['site_name'] ?> Geocache Search Results, downloaded via OKAPI - <?= $vars['installation']['okapi_base_url'] . ($vars['alt_wpts'] && $vars['ns_gsak'] ? ' (HasChildren)' : '') ?></desc>
|
||||
<author><?= $vars['installation']['site_name'] ?></author>
|
||||
<url><?= $vars['installation']['site_url'] ?></url>
|
||||
<urlname><?= $vars['installation']['site_name'] ?></urlname>
|
||||
<time><?= date('c') ?></time>
|
||||
<? foreach ($vars['caches'] as $c) { ?>
|
||||
<? list($lat, $lon) = explode("|", $c['location']); ?>
|
||||
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
||||
<time><?= $c['date_created'] ?></time>
|
||||
<name><?= $c['code'] ?></name>
|
||||
<desc><?= Okapi::xmlescape(isset($c['name_2']) ? $c['name_2'] : $c['name']) ?> <?= _("hidden by") ?> <?= Okapi::xmlescape($c['owner']['username']) ?> :: <?= ucfirst($c['type']) ?> Cache (<?= $c['difficulty'] ?>/<?= $c['terrain'] ?><? if ($c['size'] !== null) { echo "/".$c['size']; } else { echo "/X"; } ?>/<?= $c['rating'] ?>)</desc>
|
||||
<url><?= $c['url'] ?></url>
|
||||
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
||||
<sym><?= ($vars['mark_found'] && $c['is_found']) ? "Geocache Found" : "Geocache" ?></sym>
|
||||
<type>Geocache|<?= $vars['cache_GPX_types'][$c['type']] ?></type>
|
||||
<? if ($vars['ns_ground']) { /* Does user want us to include Groundspeak's <cache> element? */ ?>
|
||||
<groundspeak:cache archived="<?= ($c['status'] == 'Archived') ? "True" : "False" ?>" available="<?= ($c['status'] == 'Available') ? "True" : "False" ?>" id="<?= $c['internal_id'] ?>" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0/1">
|
||||
<groundspeak:name><?= Okapi::xmlescape(isset($c['name_2']) ? $c['name_2'] : $c['name']) ?></groundspeak:name>
|
||||
<groundspeak:placed_by><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:placed_by>
|
||||
<groundspeak:owner id="<?= $vars['user_uuid_to_internal_id'][$c['owner']['uuid']] ?>"><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:owner>
|
||||
<groundspeak:type><?= $vars['cache_GPX_types'][$c['type']] ?></groundspeak:type>
|
||||
<groundspeak:container><?= $vars['cache_GPX_sizes'][$c['size2']] ?></groundspeak:container>
|
||||
<? if ($vars['gc_attrs'] || $vars['gc_ocde_attrs']) { /* Does user want us to include groundspeak:attributes? */ ?>
|
||||
<groundspeak:attributes>
|
||||
<?
|
||||
foreach ($c['gc_attrs'] as $gc_id => $gc_attr) {
|
||||
print "<groundspeak:attribute id=\"".$gc_id."\" ";
|
||||
print "inc=\"".$gc_attr['inc']."\">";
|
||||
print Okapi::xmlescape($gc_attr['name']);
|
||||
print "</groundspeak:attribute>";
|
||||
}
|
||||
?>
|
||||
</groundspeak:attributes>
|
||||
<? } ?>
|
||||
<groundspeak:difficulty><?= $c['difficulty'] ?></groundspeak:difficulty>
|
||||
<groundspeak:terrain><?= $c['terrain'] ?></groundspeak:terrain>
|
||||
<? if ($c['short_description']) { ?>
|
||||
<groundspeak:short_description html="False"><?= Okapi::xmlescape($c['short_description']) ?></groundspeak:short_description>
|
||||
<? } ?>
|
||||
<groundspeak:long_description html="True">
|
||||
<? if (isset($c['warning_prefix'])) { ?>
|
||||
<p style='font-size: 120%'><?= Okapi::xmlescape($c['warning_prefix']) ?></p>
|
||||
<? } ?>
|
||||
<p>
|
||||
<a href="<?= $c['url'] ?>"><?= Okapi::xmlescape($c['name']) ?></a>
|
||||
<?= _("hidden by") ?> <a href='<?= $c['owner']['profile_url'] ?>'><?= Okapi::xmlescape($c['owner']['username']) ?></a><br/>
|
||||
<? if ($vars['recommendations'] == 'desc:count') { /* Does user want us to include recommendations count? */ ?>
|
||||
<?= sprintf(ngettext("%d recommendation", "%d recommendations", $c['recommendations']), $c['recommendations']) ?>
|
||||
(<?= sprintf(ngettext("found %d time", "found %d times", $c['founds']), $c['founds']) ?>).
|
||||
<? } ?>
|
||||
<? if ($vars['trackables'] == 'desc:count') { /* Does user want us to include trackables count? */ ?>
|
||||
<?= sprintf(ngettext("%d trackable", "%d trackables", $c['trackables_count']), $c['trackables_count']) ?>.
|
||||
<? } ?>
|
||||
</p>
|
||||
<? if ((in_array('desc:text', $vars['my_notes'])) && ($c['my_notes'] != null)) { /* Does user want us to include personal notes? */ ?>
|
||||
<p><b><?= _("Personal notes") ?>:</b><br><?= Okapi::xmlescape(nl2br($c['my_notes'])) ?></p>
|
||||
<? } ?>
|
||||
|
||||
<? if (in_array('desc:text', $vars['attrs']) && count($c['attrnames']) > 0) { /* Does user want us to include attributes? */ ?>
|
||||
<p><?= _("Attributes") ?>:</p>
|
||||
<ul><li><?= implode("</li><li>", $c['attrnames']) ?></li></ul>
|
||||
<? } ?>
|
||||
<? if ($vars['trackables'] == 'desc:list' && count($c['trackables']) > 0) { /* Does user want us to include trackables list? */ ?>
|
||||
<p><?= _("Trackables") ?>:</p>
|
||||
<ul>
|
||||
<? foreach ($c['trackables'] as $t) { ?>
|
||||
<li><a href='<?= Okapi::xmlescape($t['url']) ?>'><?= Okapi::xmlescape($t['name']) ?></a> (<?= $t['code'] ?>)</li>
|
||||
<? } ?>
|
||||
</ul>
|
||||
<? } ?>
|
||||
<?= Okapi::xmlescape($c['description']) ?>
|
||||
<? if ((strpos($vars['images'], "descrefs:") === 0) && count($c['images']) > 0) { /* Does user want us to include <img> references in cache descriptions? */
|
||||
if ($vars['images'] == "descrefs:thumblinks") { ?>
|
||||
<h2><?= _("Images") ?> (<?= count($c['images']) ?>)</h2>
|
||||
<div>
|
||||
<? foreach ($c['images'] as $img) { ?>
|
||||
<div style='float:left; padding:6px'><a href='<?= Okapi::xmlescape($img['url']) ?>'><img src='<?= Okapi::xmlescape($img['thumb_url']) ?>'></a><br>
|
||||
<?= Okapi::xmlescape($img['caption']) ?></div>
|
||||
<? } ?>
|
||||
</div>
|
||||
<? } else {
|
||||
# We will split images into two subcategories: spoilers and nonspoilers.
|
||||
$spoilers = array();
|
||||
$nonspoilers = array();
|
||||
foreach ($c['images'] as $img)
|
||||
if ($img['is_spoiler']) $spoilers[] = $img;
|
||||
else $nonspoilers[] = $img;
|
||||
?>
|
||||
<? if (count($nonspoilers) > 0) { ?>
|
||||
<h2><?= _("Images") ?> (<?= count($nonspoilers) ?>)</h2>
|
||||
<? foreach ($nonspoilers as $img) { ?>
|
||||
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
||||
<?= Okapi::xmlescape($img['caption']) ?></p>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? if (count($spoilers) > 0 && $vars['images'] == 'descrefs:all') { ?>
|
||||
<h2><?= _("Spoilers") ?> (<?= count($spoilers) ?>)</h2>
|
||||
<? foreach ($spoilers as $img) { ?>
|
||||
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
||||
<?= Okapi::xmlescape($img['caption']) ?></p>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? if ((strpos($vars['images'], "ox:") === 0) && count($c['images']) > 0) { /* Include image descriptions (for ox:image numbers)? */ ?>
|
||||
<p><?= _("Image descriptions") ?>:</p>
|
||||
<ul>
|
||||
<? foreach ($c['images'] as $no => $img) { ?>
|
||||
<li><?= $img['unique_caption'] ?>. <?= Okapi::xmlescape($img['caption']) ?></li>
|
||||
<? } ?>
|
||||
</ul>
|
||||
<? } ?>
|
||||
<? if ($vars['protection_areas'] == 'desc:text' && count($c['protection_areas'])) { ?>
|
||||
<p><?= _("The cache probably is located in the following protection areas:") ?></p>
|
||||
<ul>
|
||||
<? foreach($c['protection_areas'] as $protection_area) { ?>
|
||||
<li><?= Okapi::xmlescape($protection_area['type'])." - ".Okapi::xmlescape($protection_area['name']) ?></li>
|
||||
<? } ?>
|
||||
</ul;>
|
||||
<? } ?>
|
||||
</groundspeak:long_description>
|
||||
<groundspeak:encoded_hints><?= Okapi::xmlescape($c['hint2']) ?></groundspeak:encoded_hints>
|
||||
<? if ((in_array('gc:personal_note', $vars['my_notes'])) && ($c['my_notes'] != null)) { /* Does user want us to include personal notes? -> Issue 294 */ ?>
|
||||
<groundspeak:personal_note><?= Okapi::xmlescape($c['my_notes']) ?></groundspeak:personal_note>
|
||||
<? } ?>
|
||||
<? if ($vars['latest_logs']) { /* Does user want us to include latest log entries? */ ?>
|
||||
<groundspeak:logs>
|
||||
<? foreach ($c['latest_logs'] as $log) { ?>
|
||||
<groundspeak:log id="<?= $log['internal_id'] ?>">
|
||||
<groundspeak:date><?= $log['date'] ?></groundspeak:date>
|
||||
<groundspeak:type><?= $log['type'] ?></groundspeak:type>
|
||||
<groundspeak:finder id="<?= $vars['user_uuid_to_internal_id'][$log['user']['uuid']] ?>"><?= Okapi::xmlescape($log['user']['username']) ?></groundspeak:finder>
|
||||
<groundspeak:text encoded="False"><?= $log['was_recommended'] ? "(*) ": "" ?><?= Okapi::xmlescape($log['comment']) ?></groundspeak:text>
|
||||
</groundspeak:log>
|
||||
<? } ?>
|
||||
</groundspeak:logs>
|
||||
<? } ?>
|
||||
<? /* groundspeak:travelbugs - does it actually DO anything? WRTODO */ ?>
|
||||
</groundspeak:cache>
|
||||
<? } ?>
|
||||
<? if ($vars['ns_ox']) { /* Does user want us to include Garmin's <opencaching> element? */ ?>
|
||||
<ox:opencaching xmlns:ox="http://www.opencaching.com/xmlschemas/opencaching/1/0">
|
||||
<ox:ratings>
|
||||
<? if ($c['rating'] !== null) { ?><ox:awesomeness><?= $c['rating'] ?></ox:awesomeness><? } ?>
|
||||
<ox:difficulty><?= $c['difficulty'] ?></ox:difficulty>
|
||||
<? if ($c['oxsize'] !== null) { ?><ox:size><?= $c['oxsize'] ?></ox:size><? } ?>
|
||||
<ox:terrain><?= $c['terrain'] ?></ox:terrain>
|
||||
</ox:ratings>
|
||||
<? if (in_array('ox:tags', $vars['attrs']) && count($c['attrnames']) > 0) { /* Does user want us to include ox:tags? */ ?>
|
||||
<ox:tags><ox:tag><?= implode("</ox:tag><ox:tag>", $c['attrnames']) ?></ox:tag></ox:tags>
|
||||
<? } ?>
|
||||
<? if ((strpos($vars['images'], "ox:") === 0) && count($c['images']) > 0) { /* Does user want us to include ox:image references? */ ?>
|
||||
<ox:images>
|
||||
<? foreach ($c['images'] as $no => $img) { ?>
|
||||
<ox:image>
|
||||
<ox:name><?= $img['unique_caption'] ?>.jpg</ox:name>
|
||||
<ox:size>0</ox:size>
|
||||
<ox:required>false</ox:required>
|
||||
<ox:spoiler><?= ($img['is_spoiler'] ? "true" : "false") ?></ox:spoiler>
|
||||
</ox:image>
|
||||
<? } ?>
|
||||
</ox:images>
|
||||
<? } ?>
|
||||
</ox:opencaching>
|
||||
<? } ?>
|
||||
</wpt>
|
||||
<? if ($vars['alt_wpts']) { ?>
|
||||
<? foreach ($c['alt_wpts'] as $wpt) { ?>
|
||||
<? list($lat, $lon) = explode("|", $wpt['location']); ?>
|
||||
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
||||
<time><?= $c['date_created'] ?></time>
|
||||
<name><?= Okapi::xmlescape($wpt['name']) ?></name>
|
||||
<cmt><?= Okapi::xmlescape($wpt['description']) ?></cmt>
|
||||
<desc><?= Okapi::xmlescape($wpt['type_name']) ?></desc>
|
||||
<url><?= $c['url'] ?></url>
|
||||
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
||||
<sym><?= $wpt['sym'] ?></sym>
|
||||
<type>Waypoint|<?= $wpt['sym'] ?></type>
|
||||
<? if ($vars['ns_gsak']) { ?>
|
||||
<gsak:wptExtension xmlns:gsak="http://www.gsak.net/xmlv1/5">
|
||||
<gsak:Parent><?= $c['code'] ?></gsak:Parent>
|
||||
</gsak:wptExtension>
|
||||
<? } ?>
|
||||
</wpt>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? if (in_array('desc:text', $vars['attrs']) && count($c['attrnames']) > 0) { /* Does user want us to include attributes? */ ?>
|
||||
<p><?= _("Attributes") ?>:</p>
|
||||
<ul><li><?= implode("</li><li>", $c['attrnames']) ?></li></ul>
|
||||
<? } ?>
|
||||
<? if ($vars['trackables'] == 'desc:list' && count($c['trackables']) > 0) { /* Does user want us to include trackables list? */ ?>
|
||||
<p><?= _("Trackables") ?>:</p>
|
||||
<ul>
|
||||
<? foreach ($c['trackables'] as $t) { ?>
|
||||
<li><a href='<?= Okapi::xmlescape($t['url']) ?>'><?= Okapi::xmlescape($t['name']) ?></a> (<?= $t['code'] ?>)</li>
|
||||
<? } ?>
|
||||
</ul>
|
||||
<? } ?>
|
||||
<?= Okapi::xmlescape($c['description']) ?>
|
||||
<? if ((strpos($vars['images'], "descrefs:") === 0) && count($c['images']) > 0) { /* Does user want us to include <img> references in cache descriptions? */
|
||||
if ($vars['images'] == "descrefs:thumblinks") { ?>
|
||||
<h2><?= _("Images") ?> (<?= count($c['images']) ?>)</h2>
|
||||
<div>
|
||||
<? foreach ($c['images'] as $img) { ?>
|
||||
<div style='float:left; padding:6px'><a href='<?= Okapi::xmlescape($img['url']) ?>'><img src='<?= Okapi::xmlescape($img['thumb_url']) ?>'></a><br>
|
||||
<?= Okapi::xmlescape($img['caption']) ?></div>
|
||||
<? } ?>
|
||||
</div>
|
||||
<? } else {
|
||||
# We will split images into two subcategories: spoilers and nonspoilers.
|
||||
$spoilers = array();
|
||||
$nonspoilers = array();
|
||||
foreach ($c['images'] as $img)
|
||||
if ($img['is_spoiler']) $spoilers[] = $img;
|
||||
else $nonspoilers[] = $img;
|
||||
?>
|
||||
<? if (count($nonspoilers) > 0) { ?>
|
||||
<h2><?= _("Images") ?> (<?= count($nonspoilers) ?>)</h2>
|
||||
<? foreach ($nonspoilers as $img) { ?>
|
||||
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
||||
<?= Okapi::xmlescape($img['caption']) ?></p>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? if (count($spoilers) > 0 && $vars['images'] == 'descrefs:all') { ?>
|
||||
<h2><?= _("Spoilers") ?> (<?= count($spoilers) ?>)</h2>
|
||||
<? foreach ($spoilers as $img) { ?>
|
||||
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
||||
<?= Okapi::xmlescape($img['caption']) ?></p>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? if ((strpos($vars['images'], "ox:") === 0) && count($c['images']) > 0) { /* Include image descriptions (for ox:image numbers)? */ ?>
|
||||
<p><?= _("Image descriptions") ?>:</p>
|
||||
<ul>
|
||||
<? foreach ($c['images'] as $no => $img) { ?>
|
||||
<li><?= $img['unique_caption'] ?>. <?= Okapi::xmlescape($img['caption']) ?></li>
|
||||
<? } ?>
|
||||
</ul>
|
||||
<? } ?>
|
||||
<? if ($vars['protection_areas'] == 'desc:text' && count($c['protection_areas'])) { ?>
|
||||
<p><?= _("The cache probably is located in the following protection areas:") ?></p>
|
||||
<ul>
|
||||
<? foreach($c['protection_areas'] as $protection_area) { ?>
|
||||
<li><?= Okapi::xmlescape($protection_area['type'])." - ".Okapi::xmlescape($protection_area['name']) ?></li>
|
||||
<? } ?>
|
||||
</ul;>
|
||||
<? } ?>
|
||||
</groundspeak:long_description>
|
||||
<groundspeak:encoded_hints><?= Okapi::xmlescape($c['hint2']) ?></groundspeak:encoded_hints>
|
||||
<? if ((in_array('gc:personal_note', $vars['my_notes'])) && ($c['my_notes'] != null)) { /* Does user want us to include personal notes? -> Issue 294 */ ?>
|
||||
<groundspeak:personal_note><?= Okapi::xmlescape($c['my_notes']) ?></groundspeak:personal_note>
|
||||
<? } ?>
|
||||
<? if ($vars['latest_logs']) { /* Does user want us to include latest log entries? */ ?>
|
||||
<groundspeak:logs>
|
||||
<? foreach ($c['latest_logs'] as $log) { ?>
|
||||
<groundspeak:log id="<?= $log['internal_id'] ?>">
|
||||
<groundspeak:date><?= $log['date'] ?></groundspeak:date>
|
||||
<groundspeak:type><?= $log['type'] ?></groundspeak:type>
|
||||
<groundspeak:finder id="<?= $vars['user_uuid_to_internal_id'][$log['user']['uuid']] ?>"><?= Okapi::xmlescape($log['user']['username']) ?></groundspeak:finder>
|
||||
<groundspeak:text encoded="False"><?= $log['was_recommended'] ? "(*) ": "" ?><?= Okapi::xmlescape($log['comment']) ?></groundspeak:text>
|
||||
</groundspeak:log>
|
||||
<? } ?>
|
||||
</groundspeak:logs>
|
||||
<? } ?>
|
||||
<? /* groundspeak:travelbugs - does it actually DO anything? WRTODO */ ?>
|
||||
</groundspeak:cache>
|
||||
<? } ?>
|
||||
<? if ($vars['ns_ox']) { /* Does user want us to include Garmin's <opencaching> element? */ ?>
|
||||
<ox:opencaching xmlns:ox="http://www.opencaching.com/xmlschemas/opencaching/1/0">
|
||||
<ox:ratings>
|
||||
<? if ($c['rating'] !== null) { ?><ox:awesomeness><?= $c['rating'] ?></ox:awesomeness><? } ?>
|
||||
<ox:difficulty><?= $c['difficulty'] ?></ox:difficulty>
|
||||
<? if ($c['oxsize'] !== null) { ?><ox:size><?= $c['oxsize'] ?></ox:size><? } ?>
|
||||
<ox:terrain><?= $c['terrain'] ?></ox:terrain>
|
||||
</ox:ratings>
|
||||
<? if (in_array('ox:tags', $vars['attrs']) && count($c['attrnames']) > 0) { /* Does user want us to include ox:tags? */ ?>
|
||||
<ox:tags><ox:tag><?= implode("</ox:tag><ox:tag>", $c['attrnames']) ?></ox:tag></ox:tags>
|
||||
<? } ?>
|
||||
<? if ((strpos($vars['images'], "ox:") === 0) && count($c['images']) > 0) { /* Does user want us to include ox:image references? */ ?>
|
||||
<ox:images>
|
||||
<? foreach ($c['images'] as $no => $img) { ?>
|
||||
<ox:image>
|
||||
<ox:name><?= $img['unique_caption'] ?>.jpg</ox:name>
|
||||
<ox:size>0</ox:size>
|
||||
<ox:required>false</ox:required>
|
||||
<ox:spoiler><?= ($img['is_spoiler'] ? "true" : "false") ?></ox:spoiler>
|
||||
</ox:image>
|
||||
<? } ?>
|
||||
</ox:images>
|
||||
<? } ?>
|
||||
</ox:opencaching>
|
||||
<? } ?>
|
||||
</wpt>
|
||||
<? if ($vars['alt_wpts']) { ?>
|
||||
<? foreach ($c['alt_wpts'] as $wpt) { ?>
|
||||
<? list($lat, $lon) = explode("|", $wpt['location']); ?>
|
||||
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
||||
<time><?= $c['date_created'] ?></time>
|
||||
<name><?= Okapi::xmlescape($wpt['name']) ?></name>
|
||||
<cmt><?= Okapi::xmlescape($wpt['description']) ?></cmt>
|
||||
<desc><?= Okapi::xmlescape($wpt['type_name']) ?></desc>
|
||||
<url><?= $c['url'] ?></url>
|
||||
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
||||
<sym><?= $wpt['sym'] ?></sym>
|
||||
<type>Waypoint|<?= $wpt['sym'] ?></type>
|
||||
<? if ($vars['ns_gsak']) { ?>
|
||||
<gsak:wptExtension xmlns:gsak="http://www.gsak.net/xmlv1/5">
|
||||
<gsak:Parent><?= $c['code'] ?></gsak:Parent>
|
||||
</gsak:wptExtension>
|
||||
<? } ?>
|
||||
</wpt>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
</gpx>
|
||||
|
@ -12,51 +12,51 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cache_code = $request->get_parameter('cache_code');
|
||||
if (!$cache_code) throw new ParamMissing('cache_code');
|
||||
if (strpos($cache_code, "|") !== false) throw new InvalidParam('cache_code');
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "code|name|location|type|status";
|
||||
$log_fields = $request->get_parameter('log_fields');
|
||||
if (!$log_fields) $log_fields = "uuid|date|user|type|comment";
|
||||
$lpc = $request->get_parameter('lpc');
|
||||
if (!$lpc) $lpc = 10;
|
||||
$attribution_append = $request->get_parameter('attribution_append');
|
||||
if (!$attribution_append) $attribution_append = 'full';
|
||||
$params = array(
|
||||
'cache_codes' => $cache_code,
|
||||
'langpref' => $langpref,
|
||||
'fields' => $fields,
|
||||
'attribution_append' => $attribution_append,
|
||||
'lpc' => $lpc,
|
||||
'log_fields' => $log_fields
|
||||
);
|
||||
$my_location = $request->get_parameter('my_location');
|
||||
if ($my_location)
|
||||
$params['my_location'] = $my_location;
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
if ($user_uuid)
|
||||
$params['user_uuid'] = $user_uuid;
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cache_code = $request->get_parameter('cache_code');
|
||||
if (!$cache_code) throw new ParamMissing('cache_code');
|
||||
if (strpos($cache_code, "|") !== false) throw new InvalidParam('cache_code');
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "code|name|location|type|status";
|
||||
$log_fields = $request->get_parameter('log_fields');
|
||||
if (!$log_fields) $log_fields = "uuid|date|user|type|comment";
|
||||
$lpc = $request->get_parameter('lpc');
|
||||
if (!$lpc) $lpc = 10;
|
||||
$attribution_append = $request->get_parameter('attribution_append');
|
||||
if (!$attribution_append) $attribution_append = 'full';
|
||||
$params = array(
|
||||
'cache_codes' => $cache_code,
|
||||
'langpref' => $langpref,
|
||||
'fields' => $fields,
|
||||
'attribution_append' => $attribution_append,
|
||||
'lpc' => $lpc,
|
||||
'log_fields' => $log_fields
|
||||
);
|
||||
$my_location = $request->get_parameter('my_location');
|
||||
if ($my_location)
|
||||
$params['my_location'] = $my_location;
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
if ($user_uuid)
|
||||
$params['user_uuid'] = $user_uuid;
|
||||
|
||||
# There's no need to validate the fields/lpc parameters as the 'geocaches'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
# There's no need to validate the fields/lpc parameters as the 'geocaches'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
|
||||
$results = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, $params));
|
||||
$result = $results[$cache_code];
|
||||
if ($result === null)
|
||||
throw new InvalidParam('cache_code', "This cache does not exist.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$results = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, $params));
|
||||
$result = $results[$cache_code];
|
||||
if ($result === null)
|
||||
throw new InvalidParam('cache_code', "This cache does not exist.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,413 +1,440 @@
|
||||
<xml>
|
||||
<brief>Retrieve information on a single geocache</brief>
|
||||
<issue-id>19</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve information on a single geocache.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>Unique code of the geocache</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for fields like
|
||||
<b>name</b> and <b>description</b>.</p>
|
||||
<p>Please note, that you may also access caches' descriptions in all
|
||||
available languages. If you want to do this, you should use fields
|
||||
<b>names</b>, <b>descriptions</b> (etc.) instead of <b>name</b> and
|
||||
<b>description</b> (etc.).</p>
|
||||
</opt>
|
||||
<opt name='fields' default='code|name|location|type|status'>
|
||||
<p>Pipe-separated list of field names which you are interested with.
|
||||
Selected fields will be included in the response. See below for the
|
||||
list of available fields.</p>
|
||||
</opt>
|
||||
<opt name='attribution_append' default='full'>
|
||||
<p>By default, OKAPI appends the value of <b>attribution_note</b> field to all the
|
||||
cache descriptions. If you would like to display the attribution note separately,
|
||||
you may use this parameter. Use one of the following values:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>full</b> - OKAPI will append the attribution note to the descriptions of the
|
||||
geocache. The language of the note will match the language of the description
|
||||
(i.e. each value in <b>descriptions</b> may contain attribution notes in
|
||||
a different language).
|
||||
</li>
|
||||
<li>
|
||||
<p><b>none</b> - OKAPI will not append the attribution note to geocache
|
||||
descriptions. You will use the <b>attribution_note</b> instead (which depends
|
||||
on the <b>langpref</b> parameter).</p>
|
||||
|
||||
<p><b>Important note:</b> You are still <b>required</b> to display the
|
||||
<b>attribution_note</b> field in some other way.</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>static</b> - OKAPI will append a "static" attribution note to the descriptions
|
||||
of the geocache. This might equal the "full" attribution note, but not necessarilly,
|
||||
since the "full" note may contain a current date
|
||||
(<a href='https://code.google.com/p/opencaching-api/issues/detail?id=178'>why?</a>),
|
||||
and the "static" note will not. This is implemented primarily for internal use
|
||||
(i.e. the replicate module). Usually you should not use it, because on some
|
||||
installations the static note will not be sufficient to meet the data license
|
||||
requirements.
|
||||
</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name='lpc' default='10'>
|
||||
Log-entries per cache - the number of logs returned in the <b>latest_logs</b> field.
|
||||
This should be an integer or a special "all" value. Please note, that you must include
|
||||
the <b>latest_logs</b> field in <b>fields</b> in order to see the log entries.
|
||||
</opt>
|
||||
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
||||
Pipe-separated list of log fields to include in the <b>latest_logs</b> field.
|
||||
For valid field names, see <b>logs/entry</b> method.
|
||||
</opt>
|
||||
<opt name='my_location'>
|
||||
<p>The reference point for cache distance and bearing calculation (typically - the user's location),
|
||||
in the "lat|lon" format. This parameter is required when accessing <b>distance</b> and/or <b>bearing</b>
|
||||
fields.</p>
|
||||
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||
longitudes in the eastern hemisphere (and negative for southern and
|
||||
western hemispheres accordingly). These are full degrees with a dot
|
||||
as a decimal point (ex. "54.3|22.3").</p>
|
||||
</opt>
|
||||
<opt name="user_uuid">
|
||||
<p>User'd ID. Required to access fields like <b>is_found</b> using <b>Level 1</b> Authentication.</p>
|
||||
<p>Please note that if you want to access private fields (like <b>my_notes</b>), then
|
||||
this parameter won't help you. You have to use <b>Level 3</b> Authentication instead.</p>
|
||||
<p>If you use <b>Level 3</b> Authentication, you shouldn't use this parameter. Or, to be exact:</p>
|
||||
<ul>
|
||||
<li><b>user_uuid</b> will be extracted from the Access Token you use. You don't have to provide it.</li>
|
||||
<li>If you provide <b>user_uuid</b>, then it HAS TO match your Access Token. If it doesn't, OKAPI
|
||||
will respond with HTTP 400 error.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>code</b> - unique Opencaching code of the geocache,</li>
|
||||
<li><b>name</b> - name of the geocache,</li>
|
||||
<li><b>names</b> - a dictionary (language code => plain-text string) of
|
||||
names of the geocache (at this time, there will be only one language,
|
||||
but this may change in future),</li>
|
||||
<li><b>location</b> - location of the cache in the "lat|lon" format
|
||||
(<i>lat</i> and <i>lon</i> are in full degrees with a dot as a decimal point),</li>
|
||||
<li>
|
||||
<p><b>type</b> - cache type. This might be <b>pretty much everything</b>,
|
||||
but there are some predefined types that you might want to treat
|
||||
in a special way (separate icons etc.). Primary types include: </p>
|
||||
<ul>
|
||||
<li><b>Traditional</b>,</li>
|
||||
<li><b>Multi</b>,</li>
|
||||
<li><b>Quiz</b>,</li>
|
||||
<li><b>Virtual</b>,</li>
|
||||
<li><b>Event</b>,</li>
|
||||
<li><i>(any other value is valid too)</i></li>
|
||||
</ul>
|
||||
<p><b>Event</b> is a peculiar type of geocache which is NOT a geocache
|
||||
at all, but it <b>is</b> stored as a geocache in OC database (this design
|
||||
decision is old as the OC network itself!). Just keep in mind, that
|
||||
in case of Event Caches, some fields may have a little different meaning
|
||||
than you would tell by their name.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>status</b> - cache status. Valid cache status codes currently include:</p>
|
||||
<ul>
|
||||
<li><b>Available</b> - Cache is available and ready for search,</li>
|
||||
<li><b>Temporarily unavailable</b> - Cache is probably unavailable (i.e. in need of maintenance)</li>
|
||||
<li><b>Archived</b> - Cache is permanently unavailable (moved to the archives).</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>url</b> - URL of the cache's web page,</li>
|
||||
<li>
|
||||
<p><b>owner</b> - dictionary of:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - geocache owner's user ID,</li>
|
||||
<li><b>username</b> - name of the user,</li>
|
||||
<li><b>profile_url</b> - URL of the user profile page,</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>gc_code</b> - Geocaching.com code (GC code) of the geocache
|
||||
<b>or null</b> if the cache is not listed on GC or the GC code is
|
||||
unknown.</p>
|
||||
|
||||
<p>Please note that this information is supplied by cache owners
|
||||
and it is often missing, obsolete or otherwise incorrect.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>distance</b> - float, the distance to a cache, in meters.
|
||||
This requires <b>my_location</b> parameter to be provided.</p>
|
||||
<p>Please note, that sometimes it is faster to compute this yourself, on client-side, instead of querying OKAPI.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>bearing</b> - float, the absolute bearing to the cache, measured in degrees from north,
|
||||
<b>or null</b> if it cannot be calculated (i.e. when you are exactly at the target's location).
|
||||
This requires <b>my_location</b> parameter to be provided.</p>
|
||||
<p>Please note, that sometimes it is faster to compute this yourself, on client-side, instead of querying OKAPI.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>bearing2</b> - string, the absolute bearing to the cache, represented as a typical direction
|
||||
string of length of 1 or 2 characters (ex. "N", "NE", "E", "SE", etc.), or "n/a" if it cannot be calculated.
|
||||
This requires <b>my_location</b> parameter to be provided.</p>
|
||||
<p>Please note, that sometimes it is faster to compute this yourself, on client-side, instead of querying OKAPI.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>bearing3</b> - string, the absolute bearing to the cache, represented as a typical direction
|
||||
string of length of 1 or 2 or 3 characters (ex. "N", "NNE", "NE", "ENE", etc.), or "n/a" if it cannot be calculated.
|
||||
This requires <b>my_location</b> parameter to be provided.</p>
|
||||
<p>Please note, that sometimes it is faster to compute this yourself, on client-side, instead of querying OKAPI.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_found</b> - boolean, true if the user already found this cache.
|
||||
See also <b>found_status</b> parameter of the services/caches/search/all
|
||||
method.</p>
|
||||
<p>This field requires you to use the <b>user_uuid</b> parameter
|
||||
(or Level 3 Authentication). Please note, that this will also return <b>true</b>
|
||||
for attended Event Caches.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_not_found</b> - boolean, true if the user has submitted "Didn't find it" log entry for this cache.</p>
|
||||
<p>This field requires you to use the <b>user_uuid</b> parameter (or Level 3 Authentication).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_watched</b> - boolean, true if the user is watching this cache. You may consider highlighting
|
||||
such geocaches in some fashion, as the users may use this functionality to temporarily mark geocaches
|
||||
of particular interest (i.e. geocaches they plan to find today).</p>
|
||||
<p>This is private data. You will need Level 3 Authentication to access this field.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_ignored</b> - boolean, true if the user is ignoring this cache. (See also <b>exclude_ignored</b>
|
||||
parameter of all search methods.)</p>
|
||||
<p>This is private data. You will need Level 3 Authentication to access this field.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>founds</b> - number of times the geocache was successfully found
|
||||
(or attended, in case of Event Caches),</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>notfounds</b> - number of times the geocache was not found
|
||||
(in case of Event Caches this will always be zero),</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>willattends</b> - in case of Event Caches, this is the number of
|
||||
"Will attend" log entries. In case of any other cache type, it will
|
||||
be <b>zero</b> (not null, for <a href='https://code.google.com/p/opencaching-api/issues/detail?id=233'>backward
|
||||
compatibility</a>),</p>
|
||||
</li>
|
||||
<li class='deprecated'>
|
||||
<b>size</b> - deprecated
|
||||
(<a href='http://code.google.com/p/opencaching-api/issues/detail?id=155'>why?</a>),
|
||||
use <b>size2</b> instead. Float (between 1 and 5), size rating of the container, or
|
||||
<b>null</b> if geocache does not have a container,
|
||||
</li>
|
||||
<li>
|
||||
<p><b>size2</b> - string indicating the size of the container, so called
|
||||
"size2 code". One of the following values:
|
||||
'none', 'nano', 'micro', 'small', 'regular', 'large', 'xlarge', 'other'.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>oxsize</b> - float (between 1 and 5) or null, this is a size rating
|
||||
variant, compatible with the one used by opencaching.com (and lately,
|
||||
Garmin GPS devices).</p>
|
||||
<p><b>Note:</b> The mapping is undocumented and may change without notice.</p>
|
||||
<p><b>Note:</b> Some of OC's size values cannot be properly mapped to <b>oxsize</b>,
|
||||
i.e. the 'other' size.</p>
|
||||
</li>
|
||||
<li><b>difficulty</b> - float (between 1 and 5), difficulty rating of the cache,</li>
|
||||
<li><b>terrain</b> - float (between 1 and 5), terrain rating of the cache,</li>
|
||||
<li>
|
||||
<b>trip_time</b> - float, approximate total amount of time needed to
|
||||
find the cache, in hours; this will usually include the time to reach the
|
||||
cache location <em>and</em> go back (from/to a parking spot, etc.);
|
||||
<b>null</b> if unknown,
|
||||
</li>
|
||||
<li><b>trip_distance</b> - float, approximate total distance needed to
|
||||
find the cache, in kilometers; this will usually include the time to reach the
|
||||
cache location <em>and</em> go back (from/to a parking spot, etc.);
|
||||
<b>null</b> if unknown,
|
||||
</li>
|
||||
<li>
|
||||
<p><b>rating</b> - float (between 1 and 5), an overall rating of the cache,
|
||||
or <b>null</b> when the geocache does not have a sufficient amount of votes
|
||||
to have a rating.</p>
|
||||
<p>Please note: some OC installations do not use the rating/voting system. The <b>rating</b> will
|
||||
always be <b>null</b> on such installations.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>rating_votes</b> - number of votes submitted for the rating of this cache.</p>
|
||||
<p>Please note: some OC installations do not use the rating/voting system. The <b>rating_votes</b> will
|
||||
always be <b>0</b> on such installations.</p>
|
||||
</li>
|
||||
<li><b>recommendations</b> - number of recommendations for this cache,</li>
|
||||
<li><b>req_passwd</b> - boolean; states if this cache requires a password
|
||||
in order to submit a "Found it" log entry,</li>
|
||||
<li><b>description</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>,
|
||||
description of the cache,</li>
|
||||
<li><b>descriptions</b> - a dictionary (language code =>
|
||||
<a href='%OKAPI:docurl:html%'>HTML string</a>) of cache descriptions,</li>
|
||||
<li class="deprecated"><b>hint</b> - <a href='%OKAPI:docurl:html%'>HTML-encoded</a>
|
||||
string, cache hints/spoilers; deprecated
|
||||
(<a href="http://code.google.com/p/opencaching-api/issues/detail?id=261">why?</a>),
|
||||
use <b>hint2</b> instead,</li>
|
||||
<li class="deprecated"><b>hints</b> - a dictionary (language code =>
|
||||
<a href='%OKAPI:docurl:html%'>HTML-encoded</a> string) of cache hints/spoilers;
|
||||
deprecated, use hints2 instead,</li>
|
||||
<li><b>hint2</b> - plain-text string, cache hints/spoilers; in general, hints
|
||||
should not be displayed to the user unless user specifically asks for them,</li>
|
||||
<li><b>hints2</b> - a dictionary (language code =>
|
||||
plain-text string) of cache hints/spoilers,</li>
|
||||
<li>
|
||||
<p><b>images</b> - list of dictionaries, each dictionary represents one
|
||||
image saved along the cache description; each dictionary has the
|
||||
following structure:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - UUID of the image,</li>
|
||||
<li><b>url</b> - URL of the image,</li>
|
||||
<li><b>thumb_url</b> - URL of a small (thumb) version of the image,</li>
|
||||
<li><b>caption</b> - plain-text string, caption of the image,</li>
|
||||
<li><b>unique_caption</b> - plain-text string, to be used as a filename
|
||||
for Garmin's crappy images implementation (currently, they get image
|
||||
caption from the image's filename itself),</li>
|
||||
<li><b>is_spoiler</b> - boolean, if <b>true</b> then the image is
|
||||
a spoiler image and should not be displayed to the user unless
|
||||
the user explicitly asks for it,</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>preview_image</b> - On some installations, owners may select one of the <b>images</b>
|
||||
(see above) as a preview image. You are encouraged to display it as a 'teaser'
|
||||
for this cache. On other installations this functionality is disabled and you
|
||||
will always get the <b>null</b> value here.</p>
|
||||
<brief>Retrieve information on a single geocache</brief>
|
||||
<issue-id>19</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve information on a single geocache.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>Unique code of the geocache</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for fields like
|
||||
<b>name</b> and <b>description</b>.</p>
|
||||
<p>Please note, that you may also access caches' descriptions in all
|
||||
available languages. If you want to do this, you should use fields
|
||||
<b>names</b>, <b>descriptions</b> (etc.) instead of <b>name</b> and
|
||||
<b>description</b> (etc.).</p>
|
||||
</opt>
|
||||
<opt name='fields' default='code|name|location|type|status'>
|
||||
<p>Pipe-separated list of field names which you are interested with.
|
||||
Selected fields will be included in the response. See below for the
|
||||
list of available fields.</p>
|
||||
</opt>
|
||||
<opt name='attribution_append' default='full'>
|
||||
<p>By default, OKAPI appends the value of <b>attribution_note</b> field to all the
|
||||
cache descriptions. If you would like to display the attribution note separately,
|
||||
you may use this parameter. Use one of the following values:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>full</b> - OKAPI will append the attribution note to the descriptions of the
|
||||
geocache. The language of the note will match the language of the description
|
||||
(i.e. each value in <b>descriptions</b> may contain attribution notes in
|
||||
a different language).
|
||||
</li>
|
||||
<li>
|
||||
<p><b>none</b> - OKAPI will not append the attribution note to geocache
|
||||
descriptions. You will use the <b>attribution_note</b> instead (which depends
|
||||
on the <b>langpref</b> parameter).</p>
|
||||
|
||||
<p>The value of <b>preview_image</b> is either <b>null</b> or a dictionary describing
|
||||
an image. The structure of this dictionary is the same as of a single entry on
|
||||
the <b>images</b> list described above.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>attr_acodes</b> - unordered list of OKAPI geocache-attribute IDs (A-codes) with
|
||||
which the cache was tagged. Use the <b>attrs</b> module to retrieve information on
|
||||
these attributes.</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>attrnames</b> - if you don't want to dig into <b>attr_acodes</b> just now, then
|
||||
you can use these as a simple alternative. <b>attrnames</b> is an unordered list of
|
||||
names of the attributes with which the cache was tagged; the language will be
|
||||
selected based on the <b>langpref</b> parameter.
|
||||
</li>
|
||||
<li>
|
||||
<p><b>attribution_note</b> - the proper attribution note for the cache listing according
|
||||
to the local OC site's Data License. By default, this note is also appended to geocache
|
||||
descriptions (see the <b>attribution_append</b> parameter).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>latest_logs</b> - a couple of latest log entries in the cache.
|
||||
The format is the same as the one returned by the services/logs/logs method.</p>
|
||||
<p>Notice: The number of logs returned can be set with the <b>lpc</b> option.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>my_notes</b> - user's notes on the cache, in plain-text, or <b>null</b>
|
||||
if user hadn't defined any notes.</p>
|
||||
<p>This field requires you to use the <b>Level 3</b> Authentication.</p>
|
||||
</li>
|
||||
<li><b>trackables_count</b> - a total number of trackables hidden within the cache.</li>
|
||||
<li>
|
||||
<p><b>trackables</b> - list of dictionaries, each dictionary represents one
|
||||
trackable hidden within the cache container; each dictionary has the
|
||||
following structure:</p>
|
||||
<ul>
|
||||
<li><b>code</b> - code of the trackable,</li>
|
||||
<li><b>name</b> - plain text name of the trackable,</li>
|
||||
<li><b>url</b> - trackable's own webpage address <b>or null</b>, if OKAPI
|
||||
cannot automatically determine this address.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>alt_wpts</b> - list of alternate/additional waypoints associated
|
||||
with this geocache. Each item is a dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>name</b> - plain-text, short, unique "codename" for the waypoint,</li>
|
||||
<li><b>location</b> - location of the waypoint in the "lat|lon" format
|
||||
(<i>lat</i> and <i>lon</i> are in full degrees with a dot as a decimal point),</li>
|
||||
<li><b>type</b> - string, unique identifier for the type of waypoint; one
|
||||
of the following: <b>parking</b>, <b>path</b>, <b>stage</b>,
|
||||
<b>physical-stage</b>, <b>virtual-stage</b>, <b>final</b>, <b>poi</b>, <b>other</b>;
|
||||
more types may be added; unknown types should be treated as <b>other</b>,
|
||||
</li>
|
||||
<li><b>type_name</b> - string, the human-readable name of the waypoint type,
|
||||
e.g. "Parking area" or "Final location"; the language will be selected
|
||||
based on the langpref argument,
|
||||
</li>
|
||||
<li>
|
||||
<b>sym</b> - string, one of commonly recognized waypoint symbol
|
||||
names, originally introduced by Garmin in their devices and GPX
|
||||
files (e.g. "Flag, Green" or "Parking Area"),
|
||||
</li>
|
||||
<li><b>description</b> - plain-text longer description of the waypoint.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>country</b> - name of the country the cache is placed in;
|
||||
may be empty ("") if the country is unknown.</p>
|
||||
<p><b>Note:</b> This data is user-supplied and is not validated in
|
||||
any way. Consider using external geocoding services instead. Also,
|
||||
currently you have no way of knowing in which language it will appear
|
||||
in (but it *may* start to vary on the value of your <b>langpref</b>
|
||||
parameter in the future).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>state</b> - name of the state the cache is placed in;
|
||||
may be empty ("") if the state is unknown.</p>
|
||||
<p><b>Note:</b> On some installations this data is user-supplied and
|
||||
is not validated in any way. Other installations calculate it from
|
||||
cache coordinates but may have problems in border regions.
|
||||
Consider using external geocoding services instead. Also,
|
||||
currently you have no way of knowing in which language it will appear
|
||||
in (but it *may* start to vary on the value of your <b>langpref</b>
|
||||
parameter in the future).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>protection_areas</b> - list of dictionaries, each representing a
|
||||
protection area in which the cache probably is located; each dictionary
|
||||
has the following structure:</p>
|
||||
<ul>
|
||||
<li><b>type</b> - the type of the protection area, e.g.
|
||||
"National Nature Reserve",</li>
|
||||
<li><b>name</b> - the name of the protection area, e.g.
|
||||
"East Dartmoor Woods and Heaths".</li>
|
||||
</ul>
|
||||
<p>The types and names currently are in a local language of the OC site but
|
||||
may be translated depending on the <b>langpref</b> parameter in the future.</p>
|
||||
<p>Note that this information is not authoritative. It may be outdated
|
||||
or incomplete, and it is completely missing on some OC installations.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>last_found</b> - date and time (ISO 8601) when the
|
||||
geocache was last found <b>or null</b> when it hasn't been yet found.</p>
|
||||
<p>Note, that some Opencaching servers don't store the exact times along
|
||||
with the log entries.</p>
|
||||
</li>
|
||||
<li><b>last_modified</b> - date and time (ISO 8601) when the
|
||||
geocache was last modified (changed status, attributes, etc.),</li>
|
||||
<li><b>date_created</b> - date and time (ISO 8601) when the
|
||||
geocache was listed at the Opencaching site,</li>
|
||||
<li><b>date_hidden</b> - date and time (ISO 8601) when
|
||||
<ul>
|
||||
<li>the geocache was first hidden (for physical caches), or </li>
|
||||
<li>the geocache was first published (for virtual caches), or</li>
|
||||
<li>the event takes place (for event caches),</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- Note: I think cache uuids should not be ever revealed to the public.
|
||||
We have already one universally unique key - the cache code. It is uncommon
|
||||
to have multiple universally unique keys. -->
|
||||
<li><b>internal_id</b> - internal ID of the cache (<b>do not</b> use
|
||||
this, unless you know what you're doing; use the "code" as an identifier).</li>
|
||||
</ul>
|
||||
<p><b>Important note:</b> You are still <b>required</b> to display the
|
||||
<b>attribution_note</b> field in some other way.</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>static</b> - OKAPI will append a "static" attribution note to the descriptions
|
||||
of the geocache. This might equal the "full" attribution note, but not necessarilly,
|
||||
since the "full" note may contain a current date
|
||||
(<a href='https://code.google.com/p/opencaching-api/issues/detail?id=178'>why?</a>),
|
||||
and the "static" note will not. This is implemented primarily for internal use
|
||||
(i.e. the replicate module). Usually you should not use it, because on some
|
||||
installations the static note will not be sufficient to meet the data license
|
||||
requirements.
|
||||
</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name='lpc' default='10'>
|
||||
Log-entries per cache - the number of logs returned in the <b>latest_logs</b> field.
|
||||
This should be an integer or a special "all" value. Please note, that you must include
|
||||
the <b>latest_logs</b> field in <b>fields</b> in order to see the log entries.
|
||||
</opt>
|
||||
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
||||
Pipe-separated list of log fields to include in the <b>latest_logs</b> field.
|
||||
For valid field names, see <b>logs/entry</b> method.
|
||||
</opt>
|
||||
<opt name='my_location'>
|
||||
<p>The reference point for cache distance and bearing calculation (typically - the user's location),
|
||||
in the "lat|lon" format. This parameter is required when accessing <b>distance</b> and/or <b>bearing</b>
|
||||
fields.</p>
|
||||
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||
longitudes in the eastern hemisphere (and negative for southern and
|
||||
western hemispheres accordingly). These are full degrees with a dot
|
||||
as a decimal point (ex. "54.3|22.3").</p>
|
||||
</opt>
|
||||
<opt name="user_uuid">
|
||||
<p>User'd ID. Required to access fields like <b>is_found</b> using <b>Level 1</b> Authentication.</p>
|
||||
<p>Please note that if you want to access private fields (like <b>my_notes</b>), then
|
||||
this parameter won't help you. You have to use <b>Level 3</b> Authentication instead.</p>
|
||||
<p>If you use <b>Level 3</b> Authentication, you shouldn't use this parameter. Or, to be exact:</p>
|
||||
<ul>
|
||||
<li><b>user_uuid</b> will be extracted from the Access Token you use. You don't have to provide it.</li>
|
||||
<li>If you provide <b>user_uuid</b>, then it HAS TO match your Access Token. If it doesn't, OKAPI
|
||||
will respond with HTTP 400 error.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||
|
||||
<p>For example, for <i>geocache?cache_code=OP3D96&fields=type</i>
|
||||
query, the result might look something link this:</p>
|
||||
<pre>{"type": "Traditional"}</pre>
|
||||
<p>If given cache code does not exist, the method will
|
||||
respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
<ul>
|
||||
<li><b>code</b> - unique Opencaching code of the geocache,</li>
|
||||
<li><b>name</b> - name of the geocache,</li>
|
||||
<li><b>names</b> - a dictionary (language code => plain-text string) of
|
||||
names of the geocache (at this time, there will be only one language,
|
||||
but this may change in future),</li>
|
||||
<li>
|
||||
<b>location</b> - location of the cache in the "lat|lon" format
|
||||
(<i>lat</i> and <i>lon</i> are in full degrees with a dot as a decimal point),
|
||||
</li>
|
||||
<li>
|
||||
<p><b>type</b> - cache type. This might be <b>pretty much everything</b>,
|
||||
but there are some predefined types that you might want to treat
|
||||
in a special way (separate icons etc.). Primary types include: </p>
|
||||
<ul>
|
||||
<li><b>Traditional</b>,</li>
|
||||
<li><b>Multi</b>,</li>
|
||||
<li><b>Quiz</b>,</li>
|
||||
<li><b>Virtual</b>,</li>
|
||||
<li><b>Event</b>,</li>
|
||||
<li><i>(any other value is valid too)</i></li>
|
||||
</ul>
|
||||
<p><b>Event</b> is a peculiar type of geocache which is NOT a geocache
|
||||
at all, but it <b>is</b> stored as a geocache in OC database (this design
|
||||
decision is old as the OC network itself!). Just keep in mind, that
|
||||
in case of Event Caches, some fields may have a little different meaning
|
||||
than you would tell by their name.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>status</b> - cache status. Valid cache status codes currently include:</p>
|
||||
<ul>
|
||||
<li><b>Available</b> - Cache is available and ready for search,</li>
|
||||
<li><b>Temporarily unavailable</b> - Cache is probably unavailable (i.e. in need of maintenance)</li>
|
||||
<li><b>Archived</b> - Cache is permanently unavailable (moved to the archives).</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>url</b> - URL of the cache's web page,</li>
|
||||
<li>
|
||||
<p><b>owner</b> - dictionary of:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - geocache owner's user ID,</li>
|
||||
<li><b>username</b> - name of the user,</li>
|
||||
<li><b>profile_url</b> - URL of the user profile page,</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>gc_code</b> - Geocaching.com code (GC code) of the geocache
|
||||
<b>or null</b> if the cache is not listed on GC or the GC code is
|
||||
unknown.</p>
|
||||
|
||||
<p>Please note that this information is supplied by cache owners
|
||||
and it is often missing, obsolete or otherwise incorrect.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>distance</b> - float, the distance to a cache, in meters.
|
||||
This requires <b>my_location</b> parameter to be provided.</p>
|
||||
<p>Please note, that sometimes it is faster to compute this yourself, on client-side, instead of querying OKAPI.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>bearing</b> - float, the absolute bearing to the cache, measured in degrees from north,
|
||||
<b>or null</b> if it cannot be calculated (i.e. when you are exactly at the target's location).
|
||||
This requires <b>my_location</b> parameter to be provided.</p>
|
||||
<p>Please note, that sometimes it is faster to compute this yourself, on client-side, instead of querying OKAPI.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>bearing2</b> - string, the absolute bearing to the cache, represented as a typical direction
|
||||
string of length of 1 or 2 characters (ex. "N", "NE", "E", "SE", etc.), or "n/a" if it cannot be calculated.
|
||||
This requires <b>my_location</b> parameter to be provided.</p>
|
||||
<p>Please note, that sometimes it is faster to compute this yourself, on client-side, instead of querying OKAPI.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>bearing3</b> - string, the absolute bearing to the cache, represented as a typical direction
|
||||
string of length of 1 or 2 or 3 characters (ex. "N", "NNE", "NE", "ENE", etc.), or "n/a" if it cannot be calculated.
|
||||
This requires <b>my_location</b> parameter to be provided.</p>
|
||||
<p>Please note, that sometimes it is faster to compute this yourself, on client-side, instead of querying OKAPI.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_found</b> - boolean, true if the user already found this cache.
|
||||
See also <b>found_status</b> parameter of the services/caches/search/all
|
||||
method.</p>
|
||||
<p>This field requires you to use the <b>user_uuid</b> parameter
|
||||
(or Level 3 Authentication). Please note, that this will also return <b>true</b>
|
||||
for attended Event Caches.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_not_found</b> - boolean, true if the user has submitted "Didn't find it" log entry for this cache.</p>
|
||||
<p>This field requires you to use the <b>user_uuid</b> parameter (or Level 3 Authentication).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_watched</b> - boolean, true if the user is watching this cache. You may consider highlighting
|
||||
such geocaches in some fashion, as the users may use this functionality to temporarily mark geocaches
|
||||
of particular interest (i.e. geocaches they plan to find today).</p>
|
||||
<p>This is private data. You will need Level 3 Authentication to access this field.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>is_ignored</b> - boolean, true if the user is ignoring this cache. (See also <b>exclude_ignored</b>
|
||||
parameter of all search methods.)</p>
|
||||
<p>This is private data. You will need Level 3 Authentication to access this field.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>founds</b> - number of times the geocache was successfully found
|
||||
(or attended, in case of Event Caches),</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>notfounds</b> - number of times the geocache was not found
|
||||
(in case of Event Caches this will always be zero),</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>willattends</b> - in case of Event Caches, this is the number of
|
||||
"Will attend" log entries. In case of any other cache type, it will
|
||||
be <b>zero</b> (not null, for <a href='https://code.google.com/p/opencaching-api/issues/detail?id=233'>backward
|
||||
compatibility</a>),</p>
|
||||
</li>
|
||||
<li class='deprecated'>
|
||||
<b>size</b> - deprecated
|
||||
(<a href='http://code.google.com/p/opencaching-api/issues/detail?id=155'>why?</a>),
|
||||
use <b>size2</b> instead. Float (between 1 and 5), size rating of the container, or
|
||||
<b>null</b> if geocache does not have a container,
|
||||
</li>
|
||||
<li>
|
||||
<p><b>size2</b> - string indicating the size of the container, so called
|
||||
"size2 code". One of the following values:
|
||||
'none', 'nano', 'micro', 'small', 'regular', 'large', 'xlarge', 'other'.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>oxsize</b> - float (between 1 and 5) or null, this is a size rating
|
||||
variant, compatible with the one used by opencaching.com (and lately,
|
||||
Garmin GPS devices).</p>
|
||||
<p><b>Note:</b> The mapping is undocumented and may change without notice.</p>
|
||||
<p><b>Note:</b> Some of OC's size values cannot be properly mapped to <b>oxsize</b>,
|
||||
i.e. the 'other' size.</p>
|
||||
</li>
|
||||
<li><b>difficulty</b> - float (between 1 and 5), difficulty rating of the cache,</li>
|
||||
<li><b>terrain</b> - float (between 1 and 5), terrain rating of the cache,</li>
|
||||
<li>
|
||||
<b>trip_time</b> - float, approximate total amount of time needed to
|
||||
find the cache, in hours; this will usually include the time to reach the
|
||||
cache location <em>and</em> go back (from/to a parking spot, etc.);
|
||||
<b>null</b> if unknown,
|
||||
</li>
|
||||
<li><b>trip_distance</b> - float, approximate total distance needed to
|
||||
find the cache, in kilometers; this will usually include the time to reach the
|
||||
cache location <em>and</em> go back (from/to a parking spot, etc.);
|
||||
<b>null</b> if unknown,
|
||||
</li>
|
||||
<li>
|
||||
<p><b>rating</b> - float (between 1 and 5), an overall rating of the cache,
|
||||
or <b>null</b> when the geocache does not have a sufficient amount of votes
|
||||
to have a rating.</p>
|
||||
<p>Please note: some OC installations do not use the rating/voting system. The <b>rating</b> will
|
||||
always be <b>null</b> on such installations.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>rating_votes</b> - number of votes submitted for the rating of this cache.</p>
|
||||
<p>Please note: some OC installations do not use the rating/voting system. The <b>rating_votes</b> will
|
||||
always be <b>0</b> on such installations.</p>
|
||||
</li>
|
||||
<li><b>recommendations</b> - number of recommendations for this cache,</li>
|
||||
<li><b>req_passwd</b> - boolean; states if this cache requires a password
|
||||
in order to submit a "Found it" log entry,</li>
|
||||
<li><b>short_description</b> - a plaintext string with a single line (very short)
|
||||
description of the cache (kind of a "tagline text"),</li>
|
||||
<li><b>short_descriptions</b> - a dictionary (language code =>
|
||||
plaintext string) of short cache descriptions,</li>
|
||||
<li><b>description</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>,
|
||||
description of the cache,</li>
|
||||
<li><b>descriptions</b> - a dictionary (language code =>
|
||||
<a href='%OKAPI:docurl:html%'>HTML string</a>) of cache descriptions,</li>
|
||||
<li class="deprecated"><b>hint</b> - <a href='%OKAPI:docurl:html%'>HTML-encoded</a>
|
||||
string, cache hints/spoilers; deprecated
|
||||
(<a href="http://code.google.com/p/opencaching-api/issues/detail?id=261">why?</a>),
|
||||
use <b>hint2</b> instead,</li>
|
||||
<li class="deprecated"><b>hints</b> - a dictionary (language code =>
|
||||
<a href='%OKAPI:docurl:html%'>HTML-encoded</a> string) of cache hints/spoilers;
|
||||
deprecated, use hints2 instead,</li>
|
||||
<li><b>hint2</b> - plain-text string, cache hints/spoilers; in general, hints
|
||||
should not be displayed to the user unless user specifically asks for them,</li>
|
||||
<li><b>hints2</b> - a dictionary (language code =>
|
||||
plain-text string) of cache hints/spoilers,</li>
|
||||
<li>
|
||||
<p><b>images</b> - list of dictionaries, each dictionary represents one
|
||||
image saved along the cache description; each dictionary has the
|
||||
following structure:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - UUID of the image,</li>
|
||||
<li><b>url</b> - URL of the image,</li>
|
||||
<li><b>thumb_url</b> - URL of a small (thumb) version of the image,</li>
|
||||
<li><b>caption</b> - plain-text string, caption of the image,</li>
|
||||
<li><b>unique_caption</b> - plain-text string, to be used as a filename
|
||||
for Garmin's crappy images implementation (currently, they get image
|
||||
caption from the image's filename itself),</li>
|
||||
<li><b>is_spoiler</b> - boolean, if <b>true</b> then the image is
|
||||
a spoiler image and should not be displayed to the user unless
|
||||
the user explicitly asks for it,</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>preview_image</b> - On some installations, owners may select one of the <b>images</b>
|
||||
(see above) as a preview image. You are encouraged to display it as a 'teaser'
|
||||
for this cache. On other installations this functionality is disabled and you
|
||||
will always get the <b>null</b> value here.</p>
|
||||
|
||||
<p>The value of <b>preview_image</b> is either <b>null</b> or a dictionary describing
|
||||
an image. The structure of this dictionary is the same as of a single entry on
|
||||
the <b>images</b> list described above.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>attr_acodes</b> - unordered list of OKAPI geocache-attribute IDs (A-codes) with
|
||||
which the cache was tagged. Use the <b>attrs</b> module to retrieve information on
|
||||
these attributes.</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>attrnames</b> - if you don't want to dig into <b>attr_acodes</b> just now, then
|
||||
you can use these as a simple alternative. <b>attrnames</b> is an unordered list of
|
||||
names of the attributes with which the cache was tagged; the language will be
|
||||
selected based on the <b>langpref</b> parameter.
|
||||
</li>
|
||||
<li>
|
||||
<p><b>attribution_note</b> - the proper attribution note for the cache listing according
|
||||
to the local OC site's Data License. By default, this note is also appended to geocache
|
||||
descriptions (see the <b>attribution_append</b> parameter).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>latest_logs</b> - a couple of latest log entries in the cache.
|
||||
The format is the same as the one returned by the services/logs/logs method.</p>
|
||||
<p>Notice: The number of logs returned can be set with the <b>lpc</b> option.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>my_notes</b> - user's notes on the cache, in plain-text, or <b>null</b>
|
||||
if user hadn't defined any notes.</p>
|
||||
<p>This field requires you to use the <b>Level 3</b> Authentication.</p>
|
||||
</li>
|
||||
<li><b>trackables_count</b> - a total number of trackables hidden within the cache.</li>
|
||||
<li>
|
||||
<p><b>trackables</b> - list of dictionaries, each dictionary represents one
|
||||
trackable hidden within the cache container; each dictionary has the
|
||||
following structure:</p>
|
||||
<ul>
|
||||
<li><b>code</b> - code of the trackable,</li>
|
||||
<li><b>name</b> - plain text name of the trackable,</li>
|
||||
<li><b>url</b> - trackable's own webpage address <b>or null</b>, if OKAPI
|
||||
cannot automatically determine this address.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="ret_alt_wpts">
|
||||
<p><b>alt_wpts</b> - list of alternate/additional waypoints associated
|
||||
with this geocache. Each item is a dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>name</b> - plain-text, short, unique "codename" for the waypoint,</li>
|
||||
<li><b>location</b> - location of the waypoint in the "lat|lon" format
|
||||
(<i>lat</i> and <i>lon</i> are in full degrees with a dot as a decimal point),</li>
|
||||
<li>
|
||||
<p><b>type</b> - string, unique identifier for the type of waypoint;
|
||||
one of the following:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>parking</b>, <b>path</b>, <b>stage</b>, <b>physical-stage</b>,
|
||||
<b>virtual-stage</b>, <b>final</b>, <b>poi</b>, <b>other</b> - used by
|
||||
OC itself, for detailed descriptions of these you'll have to refer to
|
||||
external Opencaching documenation,</li>
|
||||
|
||||
<li><b>user-coords</b> - extra coordinates supplied <i>by the user who
|
||||
had found the cache</i> (NOT the owner of the cache), most probably
|
||||
pointing to the final location of the cache (e.g. a quiz cache);
|
||||
this type of waypoint is available only in some installations and only
|
||||
if you're using Level 3 Authentication,</li>
|
||||
|
||||
<li>more types may be added at any moment; unknown types should be
|
||||
treated as <b>other</b>.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<b>type_name</b> - string, the human-readable name of the waypoint type,
|
||||
e.g. "Parking area" or "Final location"; the language will be selected
|
||||
based on the langpref argument,
|
||||
</li>
|
||||
<li>
|
||||
<p><b>sym</b> - string, one of commonly recognized waypoint symbol
|
||||
names, originally introduced by Garmin in their devices and GPX
|
||||
files (e.g. "Flag, Green" or "Parking Area").</p>
|
||||
|
||||
<p>These symbol codes are only suggestions. They are understood by
|
||||
Garmin-related software and devices. If you don't know how to display such
|
||||
symbols, you are welcome to use any symbol you'd like in your
|
||||
application.</p>
|
||||
</li>
|
||||
<li><b>description</b> - plain-text longer description of the waypoint.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>country</b> - name of the country the cache is placed in;
|
||||
may be empty ("") if the country is unknown.</p>
|
||||
<p><b>Note:</b> This data is user-supplied and is not validated in
|
||||
any way. Consider using external geocoding services instead. Also,
|
||||
currently you have no way of knowing in which language it will appear
|
||||
in (but it *may* start to vary on the value of your <b>langpref</b>
|
||||
parameter in the future).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>state</b> - name of the state the cache is placed in;
|
||||
may be empty ("") if the state is unknown.</p>
|
||||
<p><b>Note:</b> On some installations this data is user-supplied and
|
||||
is not validated in any way. Other installations calculate it from
|
||||
cache coordinates but may have problems in border regions.
|
||||
Consider using external geocoding services instead. Also,
|
||||
currently you have no way of knowing in which language it will appear
|
||||
in (but it *may* start to vary on the value of your <b>langpref</b>
|
||||
parameter in the future).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>protection_areas</b> - list of dictionaries, each representing a
|
||||
protection area in which the cache probably is located; each dictionary
|
||||
has the following structure:</p>
|
||||
<ul>
|
||||
<li><b>type</b> - the type of the protection area, e.g.
|
||||
"National Nature Reserve",</li>
|
||||
<li><b>name</b> - the name of the protection area, e.g.
|
||||
"East Dartmoor Woods and Heaths".</li>
|
||||
</ul>
|
||||
<p>The types and names currently are in a local language of the OC site but
|
||||
may be translated depending on the <b>langpref</b> parameter in the future.</p>
|
||||
<p>Note that this information is not authoritative. It may be outdated
|
||||
or incomplete, and it is completely missing on some OC installations.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>last_found</b> - date and time (ISO 8601) when the
|
||||
geocache was last found <b>or null</b> when it hasn't been yet found.</p>
|
||||
<p>Note, that some Opencaching servers don't store the exact times along
|
||||
with the log entries.</p>
|
||||
</li>
|
||||
<li><b>last_modified</b> - date and time (ISO 8601) when the
|
||||
geocache was last modified (changed status, attributes, etc.),</li>
|
||||
<li><b>date_created</b> - date and time (ISO 8601) when the
|
||||
geocache was listed at the Opencaching site,</li>
|
||||
<li><b>date_hidden</b> - date and time (ISO 8601) when
|
||||
<ul>
|
||||
<li>the geocache was first hidden (for physical caches), or </li>
|
||||
<li>the geocache was first published (for virtual caches), or</li>
|
||||
<li>the event takes place (for event caches),</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- Note: I think cache uuids should not be ever revealed to the public.
|
||||
We have already one universally unique key - the cache code. It is uncommon
|
||||
to have multiple universally unique keys. -->
|
||||
<li><b>internal_id</b> - internal ID of the cache (<b>do not</b> use
|
||||
this, unless you know what you're doing; use the "code" as an identifier).</li>
|
||||
</ul>
|
||||
|
||||
<p>For example, for <i>geocache?cache_code=OP3D96&fields=type</i>
|
||||
query, the result might look something link this:</p>
|
||||
<pre>{"type": "Traditional"}</pre>
|
||||
<p>If given cache code does not exist, the method will
|
||||
respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
</xml>
|
File diff suppressed because it is too large
Load Diff
@ -1,51 +1,54 @@
|
||||
<xml>
|
||||
<brief>Retrieve information on multiple geocaches</brief>
|
||||
<issue-id>20</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the services/caches/geocache method, but works
|
||||
with multiple geocaches (instead of only one).</p>
|
||||
</desc>
|
||||
<req name='cache_codes'>
|
||||
<p>Pipe-separated list of cache cache codes. These represent the
|
||||
geocaches you are interested in. No more than 500 codes are allowed.
|
||||
Unlike in the "geocache" method, this CAN be an empty string (it will
|
||||
result in an empty, but valid, response).</p>
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for fields like
|
||||
<b>name</b> and <b>description</b>.</p>
|
||||
<p>Please note, that you may also access caches' descriptions in all
|
||||
available languages. If you want to do this, you should use fields
|
||||
<b>names</b>, <b>descriptions</b> (etc.) instead of <b>name</b> and
|
||||
<b>description</b> (etc.).</p>
|
||||
</opt>
|
||||
<opt name='fields' default='code|name|location|type|status'>
|
||||
<p>Same as in the services/caches/geocache method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/caches/geocache method for a list available values.</p>
|
||||
</opt>
|
||||
<opt name='attribution_append' default='full'>
|
||||
<p>Same as in the services/caches/geocache method.</p>
|
||||
</opt>
|
||||
<opt name='lpc' default='10'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<opt name='user_uuid'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. Cache codes you provide will be mapped to dictionary keys,
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>For example, for <i>geocaches?cache_codes=OP3D96|OC124&fields=type</i>
|
||||
query, the result might look something link this:</p>
|
||||
<pre>{"OP3D96": {"type": "Traditional"}, "OC124": null}</pre>
|
||||
<p>Value of <b>null</b> means that the given cache haven't been found.
|
||||
(This behavior is different than in the services/caches/geocache method, which
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
<brief>Retrieve information on multiple geocaches</brief>
|
||||
<issue-id>20</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the services/caches/geocache method, but works
|
||||
with multiple geocaches (instead of only one).</p>
|
||||
</desc>
|
||||
<req name='cache_codes'>
|
||||
<p>Pipe-separated list of cache cache codes. These represent the
|
||||
geocaches you are interested in. No more than 500 codes are allowed.
|
||||
Unlike in the "geocache" method, this CAN be an empty string (it will
|
||||
result in an empty, but valid, response).</p>
|
||||
</req>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for fields like
|
||||
<b>name</b> and <b>description</b>.</p>
|
||||
<p>Please note, that you may also access caches' descriptions in all
|
||||
available languages. If you want to do this, you should use fields
|
||||
<b>names</b>, <b>descriptions</b> (etc.) instead of <b>name</b> and
|
||||
<b>description</b> (etc.).</p>
|
||||
</opt>
|
||||
<opt name='fields' default='code|name|location|type|status'>
|
||||
<p>Same as in the services/caches/geocache method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/caches/geocache method for a list available values.</p>
|
||||
</opt>
|
||||
<opt name='attribution_append' default='full'>
|
||||
<p>Same as in the services/caches/geocache method.</p>
|
||||
</opt>
|
||||
<opt name='lpc' default='10'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<opt name='my_location'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<opt name='user_uuid'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. Cache codes you provide will be mapped to dictionary keys,
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>For example, for <i>geocaches?cache_codes=OP3D96|OC124&fields=type</i>
|
||||
query, the result might look something link this:</p>
|
||||
<pre>{"OP3D96": {"type": "Traditional"}, "OC124": null}</pre>
|
||||
<p>Value of <b>null</b> means that the given cache haven't been found.
|
||||
(This behavior is different than in the services/caches/geocache method, which
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
</xml>
|
@ -23,230 +23,246 @@ require_once 'tiletree.inc.php';
|
||||
|
||||
class ReplicateListener
|
||||
{
|
||||
public static function receive($changelog)
|
||||
{
|
||||
# This will be called every time new items arrive from replicate module's
|
||||
# changelog. The format of $changelog is described in the replicate module
|
||||
# (NOT the entire response, just the "changelog" key).
|
||||
public static function receive($changelog)
|
||||
{
|
||||
# This will be called every time new items arrive from replicate module's
|
||||
# changelog. The format of $changelog is described in the replicate module
|
||||
# (NOT the entire response, just the "changelog" key).
|
||||
|
||||
foreach ($changelog as $c)
|
||||
{
|
||||
if ($c['object_type'] == 'geocache')
|
||||
{
|
||||
if ($c['change_type'] == 'replace')
|
||||
self::handle_geocache_replace($c);
|
||||
else
|
||||
self::handle_geocache_delete($c);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($changelog as $c)
|
||||
{
|
||||
if ($c['object_type'] == 'geocache')
|
||||
{
|
||||
if ($c['change_type'] == 'replace')
|
||||
self::handle_geocache_replace($c);
|
||||
else
|
||||
self::handle_geocache_delete($c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function reset($mail_admins = true)
|
||||
{
|
||||
# This will be called when there are "too many" entries in the changelog
|
||||
# and the replicate module thinks it better to just reset the entire TileTree.
|
||||
# For the first hours after such reset maps may work a little slower.
|
||||
public static function reset($mail_admins = true)
|
||||
{
|
||||
# This will be called when there are "too many" entries in the changelog
|
||||
# and the replicate module thinks it better to just reset the entire TileTree.
|
||||
# For the first hours after such reset maps may work a little slower.
|
||||
|
||||
Db::execute("delete from okapi_tile_status");
|
||||
Db::execute("delete from okapi_tile_caches");
|
||||
}
|
||||
Db::execute("delete from okapi_tile_status");
|
||||
Db::execute("delete from okapi_tile_caches");
|
||||
}
|
||||
|
||||
private static function handle_geocache_replace($c)
|
||||
{
|
||||
# Check if any relevant geocache attributes have changed.
|
||||
# We will pick up "our" copy of the cache from zero-zoom level.
|
||||
private static function handle_geocache_replace($c)
|
||||
{
|
||||
# Check if any relevant geocache attributes have changed.
|
||||
# We will pick up "our" copy of the cache from zero-zoom level.
|
||||
|
||||
try {
|
||||
$cache = OkapiServiceRunner::call("services/caches/geocache", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
||||
'cache_code' => $c['object_key']['code'],
|
||||
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
||||
)));
|
||||
} catch (InvalidParam $e) {
|
||||
# Unprobable, but possible. Ignore changelog entry.
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$cache = OkapiServiceRunner::call("services/caches/geocache", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
||||
'cache_code' => $c['object_key']['code'],
|
||||
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
||||
)));
|
||||
} catch (InvalidParam $e) {
|
||||
# Unprobable, but possible. Ignore changelog entry.
|
||||
return;
|
||||
}
|
||||
|
||||
$theirs = TileTree::generate_short_row($cache);
|
||||
$ours = mysql_fetch_row(Db::query("
|
||||
select cache_id, z21x, z21y, status, type, rating, flags
|
||||
from okapi_tile_caches
|
||||
where
|
||||
z=0
|
||||
and cache_id = '".mysql_real_escape_string($cache['internal_id'])."'
|
||||
"));
|
||||
if (!$ours)
|
||||
{
|
||||
# Aaah, a new geocache! How nice... ;)
|
||||
# Fetch our copy of the cache.
|
||||
|
||||
self::add_geocache_to_cached_tiles($theirs);
|
||||
}
|
||||
elseif (($ours[1] != $theirs[1]) || ($ours[2] != $theirs[2])) # z21x & z21y fields
|
||||
{
|
||||
# Location changed.
|
||||
$ours = mysql_fetch_row(Db::query("
|
||||
select cache_id, z21x, z21y, status, type, rating, flags
|
||||
from okapi_tile_caches
|
||||
where
|
||||
z=0
|
||||
and cache_id = '".mysql_real_escape_string($cache['internal_id'])."'
|
||||
"));
|
||||
|
||||
self::remove_geocache_from_cached_tiles($ours[0]);
|
||||
self::add_geocache_to_cached_tiles($theirs);
|
||||
}
|
||||
elseif ($ours != $theirs)
|
||||
{
|
||||
self::update_geocache_attributes_in_cached_tiles($theirs);
|
||||
}
|
||||
else
|
||||
{
|
||||
# No need to update anything. This is very common (i.e. when the
|
||||
# cache was simply found, not actually changed). Replicate module generates
|
||||
# many updates which do not influence our cache.
|
||||
}
|
||||
}
|
||||
# Caches near the poles caused our computations to break here. We will
|
||||
# ignore such caches!
|
||||
|
||||
private static function remove_geocache_from_cached_tiles($cache_id)
|
||||
{
|
||||
# Simply remove all traces of this geocache from all tiles.
|
||||
# This includes all references along tiles' borders, etc.
|
||||
list($lat, $lon) = explode("|", $cache['location']);
|
||||
if ((floatval($lat) >= 89.99) || (floatval($lat) <= -89.99)) {
|
||||
if ($ours) {
|
||||
self::remove_geocache_from_cached_tiles($ours[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Db::execute("
|
||||
delete from okapi_tile_caches
|
||||
where cache_id = '".mysql_real_escape_string($cache_id)."'
|
||||
");
|
||||
# Compute the new row for okapi_tile_caches. Compare with the old one.
|
||||
|
||||
# Note, that after this operation, okapi_tile_status may be out-of-date.
|
||||
# There might exist some rows with status==2, but they should be in status==1.
|
||||
# Currently, we can ignore this, because status==1 is just a shortcut to
|
||||
# avoid making unnecessary queries.
|
||||
}
|
||||
$theirs = TileTree::generate_short_row($cache);
|
||||
if (!$ours)
|
||||
{
|
||||
# Aaah, a new geocache! How nice... ;)
|
||||
|
||||
private static function add_geocache_to_cached_tiles(&$row)
|
||||
{
|
||||
# This one is the most complicated. We need to identify all tiles
|
||||
# where the cache should be present. This include 22 obvious "exact match"
|
||||
# tiles (one per each zoom level), *and* all "just outside the border"
|
||||
# tiles (one geocache can be present in up to 4 tiles per zoom level).
|
||||
# This gives us max. 88 tiles to add the geocache to.
|
||||
self::add_geocache_to_cached_tiles($theirs);
|
||||
}
|
||||
elseif (($ours[1] != $theirs[1]) || ($ours[2] != $theirs[2])) # z21x & z21y fields
|
||||
{
|
||||
# Location changed.
|
||||
|
||||
$tiles_to_update = array();
|
||||
self::remove_geocache_from_cached_tiles($ours[0]);
|
||||
self::add_geocache_to_cached_tiles($theirs);
|
||||
}
|
||||
elseif ($ours != $theirs)
|
||||
{
|
||||
self::update_geocache_attributes_in_cached_tiles($theirs);
|
||||
}
|
||||
else
|
||||
{
|
||||
# No need to update anything. This is very common (i.e. when the
|
||||
# cache was simply found, not actually changed). Replicate module generates
|
||||
# many updates which do not influence our cache.
|
||||
}
|
||||
}
|
||||
|
||||
# We will begin at zoom 21 and then go down to zoom 0.
|
||||
private static function remove_geocache_from_cached_tiles($cache_id)
|
||||
{
|
||||
# Simply remove all traces of this geocache from all tiles.
|
||||
# This includes all references along tiles' borders, etc.
|
||||
|
||||
$z21x = $row[1];
|
||||
$z21y = $row[2];
|
||||
$ex = $z21x >> 8; # initially, z21x / <tile width>
|
||||
$ey = $z21y >> 8; # initially, z21y / <tile height>
|
||||
for ($zoom = 21; $zoom >= 0; $zoom--, $ex >>= 1, $ey >>= 1)
|
||||
{
|
||||
# ($ex, $ey) points to the "exact match" tile. We need to determine
|
||||
# tile-range to check for "just outside the border" tiles. We will
|
||||
# go with the simple approach and check all 1+8 bordering tiles.
|
||||
Db::execute("
|
||||
delete from okapi_tile_caches
|
||||
where cache_id = '".mysql_real_escape_string($cache_id)."'
|
||||
");
|
||||
|
||||
$tiles_in_this_region = array();
|
||||
for ($x=$ex-1; $x<=$ex+1; $x++)
|
||||
for ($y=$ey-1; $y<=$ey+1; $y++)
|
||||
if (($x >= 0) && ($x < 1<<$zoom) && ($y >= 0) && ($y < 1<<$zoom))
|
||||
$tiles_in_this_region[] = array($x, $y);
|
||||
# Note, that after this operation, okapi_tile_status may be out-of-date.
|
||||
# There might exist some rows with status==2, but they should be in status==1.
|
||||
# Currently, we can ignore this, because status==1 is just a shortcut to
|
||||
# avoid making unnecessary queries.
|
||||
}
|
||||
|
||||
foreach ($tiles_in_this_region as $coords)
|
||||
{
|
||||
list($x, $y) = $coords;
|
||||
private static function add_geocache_to_cached_tiles(&$row)
|
||||
{
|
||||
# This one is the most complicated. We need to identify all tiles
|
||||
# where the cache should be present. This include 22 obvious "exact match"
|
||||
# tiles (one per each zoom level), *and* all "just outside the border"
|
||||
# tiles (one geocache can be present in up to 4 tiles per zoom level).
|
||||
# This gives us max. 88 tiles to add the geocache to.
|
||||
|
||||
$scale = 8 + 21 - $zoom;
|
||||
$margin = 1 << ($scale - 3); # 32px of current $zoom level, measured in z21 pixels.
|
||||
$tiles_to_update = array();
|
||||
|
||||
$left_z21x = ($x << $scale) - $margin;
|
||||
$right_z21x = (($x + 1) << $scale) + $margin;
|
||||
$top_z21y = ($y << $scale) - $margin;
|
||||
$bottom_z21y = (($y + 1) << $scale) + $margin;
|
||||
# We will begin at zoom 21 and then go down to zoom 0.
|
||||
|
||||
if ($z21x < $left_z21x)
|
||||
continue;
|
||||
if ($z21x > $right_z21x)
|
||||
continue;
|
||||
if ($z21y < $top_z21y)
|
||||
continue;
|
||||
if ($z21y > $bottom_z21y)
|
||||
continue;
|
||||
$z21x = $row[1];
|
||||
$z21y = $row[2];
|
||||
$ex = $z21x >> 8; # initially, z21x / <tile width>
|
||||
$ey = $z21y >> 8; # initially, z21y / <tile height>
|
||||
for ($zoom = 21; $zoom >= 0; $zoom--, $ex >>= 1, $ey >>= 1)
|
||||
{
|
||||
# ($ex, $ey) points to the "exact match" tile. We need to determine
|
||||
# tile-range to check for "just outside the border" tiles. We will
|
||||
# go with the simple approach and check all 1+8 bordering tiles.
|
||||
|
||||
# We found a match. Store it for later.
|
||||
$tiles_in_this_region = array();
|
||||
for ($x=$ex-1; $x<=$ex+1; $x++)
|
||||
for ($y=$ey-1; $y<=$ey+1; $y++)
|
||||
if (($x >= 0) && ($x < 1<<$zoom) && ($y >= 0) && ($y < 1<<$zoom))
|
||||
$tiles_in_this_region[] = array($x, $y);
|
||||
|
||||
$tiles_to_update[] = array($zoom, $x, $y);
|
||||
}
|
||||
}
|
||||
foreach ($tiles_in_this_region as $coords)
|
||||
{
|
||||
list($x, $y) = $coords;
|
||||
|
||||
# We have a list of all possible tiles that need updating.
|
||||
# Most of these tiles aren't cached at all. We need to update
|
||||
# only the cached ones.
|
||||
$scale = 8 + 21 - $zoom;
|
||||
$margin = 1 << ($scale - 3); # 32px of current $zoom level, measured in z21 pixels.
|
||||
|
||||
$alternatives_escaped = array();
|
||||
foreach ($tiles_to_update as $coords)
|
||||
{
|
||||
list($z, $x, $y) = $coords;
|
||||
$alternatives_escaped[] = "(
|
||||
z = '".mysql_real_escape_string($z)."'
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
)";
|
||||
}
|
||||
if (count($alternatives_escaped) > 0)
|
||||
{
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
)
|
||||
select
|
||||
z, x, y,
|
||||
'".mysql_real_escape_string($row[0])."',
|
||||
'".mysql_real_escape_string($row[1])."',
|
||||
'".mysql_real_escape_string($row[2])."',
|
||||
'".mysql_real_escape_string($row[3])."',
|
||||
'".mysql_real_escape_string($row[4])."',
|
||||
".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").",
|
||||
'".mysql_real_escape_string($row[6])."'
|
||||
from okapi_tile_status
|
||||
where
|
||||
(".implode(" or ", $alternatives_escaped).")
|
||||
and status in (1,2)
|
||||
");
|
||||
$left_z21x = ($x << $scale) - $margin;
|
||||
$right_z21x = (($x + 1) << $scale) + $margin;
|
||||
$top_z21y = ($y << $scale) - $margin;
|
||||
$bottom_z21y = (($y + 1) << $scale) + $margin;
|
||||
|
||||
# We might have just filled some empty tiles (status 1) with data.
|
||||
# We need to update their status to 2.
|
||||
if ($z21x < $left_z21x)
|
||||
continue;
|
||||
if ($z21x > $right_z21x)
|
||||
continue;
|
||||
if ($z21y < $top_z21y)
|
||||
continue;
|
||||
if ($z21y > $bottom_z21y)
|
||||
continue;
|
||||
|
||||
Db::execute("
|
||||
update okapi_tile_status
|
||||
set status=2
|
||||
where
|
||||
(".implode(" or ", $alternatives_escaped).")
|
||||
and status=1
|
||||
");
|
||||
}
|
||||
# We found a match. Store it for later.
|
||||
|
||||
# And that's all. That should do the trick.
|
||||
}
|
||||
$tiles_to_update[] = array($zoom, $x, $y);
|
||||
}
|
||||
}
|
||||
|
||||
private static function update_geocache_attributes_in_cached_tiles(&$row)
|
||||
{
|
||||
# Update all attributes (for all levels). Note, that we don't need to
|
||||
# update location ($row[1] and $row[2]) - this method is called ONLY
|
||||
# when location stayed untouched!
|
||||
# We have a list of all possible tiles that need updating.
|
||||
# Most of these tiles aren't cached at all. We need to update
|
||||
# only the cached ones.
|
||||
|
||||
Db::execute("
|
||||
update okapi_tile_caches
|
||||
set
|
||||
status = '".mysql_real_escape_string($row[3])."',
|
||||
type = '".mysql_real_escape_string($row[4])."',
|
||||
rating = ".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").",
|
||||
flags = '".mysql_real_escape_string($row[6])."'
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($row[0])."'
|
||||
");
|
||||
}
|
||||
$alternatives_escaped = array();
|
||||
foreach ($tiles_to_update as $coords)
|
||||
{
|
||||
list($z, $x, $y) = $coords;
|
||||
$alternatives_escaped[] = "(
|
||||
z = '".mysql_real_escape_string($z)."'
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
)";
|
||||
}
|
||||
if (count($alternatives_escaped) > 0)
|
||||
{
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
)
|
||||
select
|
||||
z, x, y,
|
||||
'".mysql_real_escape_string($row[0])."',
|
||||
'".mysql_real_escape_string($row[1])."',
|
||||
'".mysql_real_escape_string($row[2])."',
|
||||
'".mysql_real_escape_string($row[3])."',
|
||||
'".mysql_real_escape_string($row[4])."',
|
||||
".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").",
|
||||
'".mysql_real_escape_string($row[6])."'
|
||||
from okapi_tile_status
|
||||
where
|
||||
(".implode(" or ", $alternatives_escaped).")
|
||||
and status in (1,2)
|
||||
");
|
||||
|
||||
private static function handle_geocache_delete($c)
|
||||
{
|
||||
# Simply delete the cache at all zoom levels.
|
||||
# We might have just filled some empty tiles (status 1) with data.
|
||||
# We need to update their status to 2.
|
||||
|
||||
$cache_id = Db::select_value("
|
||||
select cache_id
|
||||
from caches
|
||||
where wp_oc='".mysql_real_escape_string($c['object_key']['code'])."'
|
||||
");
|
||||
self::remove_geocache_from_cached_tiles($cache_id);
|
||||
}
|
||||
Db::execute("
|
||||
update okapi_tile_status
|
||||
set status=2
|
||||
where
|
||||
(".implode(" or ", $alternatives_escaped).")
|
||||
and status=1
|
||||
");
|
||||
}
|
||||
|
||||
# And that's all. That should do the trick.
|
||||
}
|
||||
|
||||
private static function update_geocache_attributes_in_cached_tiles(&$row)
|
||||
{
|
||||
# Update all attributes (for all levels). Note, that we don't need to
|
||||
# update location ($row[1] and $row[2]) - this method is called ONLY
|
||||
# when location stayed untouched!
|
||||
|
||||
Db::execute("
|
||||
update okapi_tile_caches
|
||||
set
|
||||
status = '".mysql_real_escape_string($row[3])."',
|
||||
type = '".mysql_real_escape_string($row[4])."',
|
||||
rating = ".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").",
|
||||
flags = '".mysql_real_escape_string($row[6])."'
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($row[0])."'
|
||||
");
|
||||
}
|
||||
|
||||
private static function handle_geocache_delete($c)
|
||||
{
|
||||
# Simply delete the cache at all zoom levels.
|
||||
|
||||
$cache_id = Db::select_value("
|
||||
select cache_id
|
||||
from caches
|
||||
where wp_oc='".mysql_real_escape_string($c['object_key']['code'])."'
|
||||
");
|
||||
self::remove_geocache_from_cached_tiles($cache_id);
|
||||
}
|
||||
}
|
@ -29,200 +29,200 @@ require_once($GLOBALS['rootpath']."okapi/services/caches/search/searching.inc.ph
|
||||
|
||||
class WebService
|
||||
{
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging the tile renderer.
|
||||
*/
|
||||
private static $USE_ETAGS_CACHE = true;
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging the tile renderer.
|
||||
*/
|
||||
private static $USE_ETAGS_CACHE = true;
|
||||
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging the tile renderer.
|
||||
*/
|
||||
private static $USE_IMAGE_CACHE = true;
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging the tile renderer.
|
||||
*/
|
||||
private static $USE_IMAGE_CACHE = true;
|
||||
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging. Grep the code to check when this flag is used.
|
||||
*/
|
||||
private static $USE_OTHER_CACHE = true;
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging. Grep the code to check when this flag is used.
|
||||
*/
|
||||
private static $USE_OTHER_CACHE = true;
|
||||
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 3
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 3
|
||||
);
|
||||
}
|
||||
|
||||
private static function require_uint($request, $name, $min_value = 0)
|
||||
{
|
||||
$val = $request->get_parameter($name);
|
||||
if ($val === null)
|
||||
throw new ParamMissing($name);
|
||||
$ret = intval($val);
|
||||
if ($ret < 0 || ("$ret" !== $val))
|
||||
throw new InvalidParam($name, "Expecting non-negative integer.");
|
||||
return $ret;
|
||||
}
|
||||
private static function require_uint($request, $name, $min_value = 0)
|
||||
{
|
||||
$val = $request->get_parameter($name);
|
||||
if ($val === null)
|
||||
throw new ParamMissing($name);
|
||||
$ret = intval($val);
|
||||
if ($ret < 0 || ("$ret" !== $val))
|
||||
throw new InvalidParam($name, "Expecting non-negative integer.");
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$checkpointA_started = microtime(true);
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$checkpointA_started = microtime(true);
|
||||
|
||||
# Make sure the request is internal.
|
||||
# Make sure the request is internal.
|
||||
|
||||
if (!in_array($request->consumer->key, array('internal', 'facade')))
|
||||
throw new BadRequest("Your Consumer Key has not been allowed to access this method.");
|
||||
if (!in_array($request->consumer->key, array('internal', 'facade')))
|
||||
throw new BadRequest("Your Consumer Key has not been allowed to access this method.");
|
||||
|
||||
# zoom, x, y - required tile-specific parameters.
|
||||
# zoom, x, y - required tile-specific parameters.
|
||||
|
||||
$zoom = self::require_uint($request, 'z');
|
||||
if ($zoom > 21)
|
||||
throw new InvalidParam('z', "Maximum value for this parameter is 21.");
|
||||
$x = self::require_uint($request, 'x');
|
||||
$y = self::require_uint($request, 'y');
|
||||
if ($x >= 1<<$zoom)
|
||||
throw new InvalidParam('x', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||
if ($y >= 1<<$zoom)
|
||||
throw new InvalidParam('y', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||
$zoom = self::require_uint($request, 'z');
|
||||
if ($zoom > 21)
|
||||
throw new InvalidParam('z', "Maximum value for this parameter is 21.");
|
||||
$x = self::require_uint($request, 'x');
|
||||
$y = self::require_uint($request, 'y');
|
||||
if ($x >= 1<<$zoom)
|
||||
throw new InvalidParam('x', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||
if ($y >= 1<<$zoom)
|
||||
throw new InvalidParam('y', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||
|
||||
# Now, we will create a search set (or use one previously created).
|
||||
# Instead of creating a new OkapiInternalRequest object, we will pass
|
||||
# the current request directly. We can do that, because we inherit all
|
||||
# of the "save" method's parameters.
|
||||
# Now, we will create a search set (or use one previously created).
|
||||
# Instead of creating a new OkapiInternalRequest object, we will pass
|
||||
# the current request directly. We can do that, because we inherit all
|
||||
# of the "save" method's parameters.
|
||||
|
||||
$search_set = OkapiServiceRunner::call('services/caches/search/save', $request);
|
||||
$set_id = $search_set['set_id'];
|
||||
$search_set = OkapiServiceRunner::call('services/caches/search/save', $request);
|
||||
$set_id = $search_set['set_id'];
|
||||
|
||||
# Get caches which are present in the result set AND within the tile
|
||||
# (+ those around the borders).
|
||||
# Get caches which are present in the result set AND within the tile
|
||||
# (+ those around the borders).
|
||||
|
||||
$rs = TileTree::query_fast($zoom, $x, $y, $set_id);
|
||||
$rows = array();
|
||||
if ($rs !== null)
|
||||
{
|
||||
while ($row = mysql_fetch_row($rs))
|
||||
$rows[] = $row;
|
||||
unset($row);
|
||||
}
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointA", null,
|
||||
microtime(true) - $checkpointA_started);
|
||||
$checkpointB_started = microtime(true);
|
||||
$rs = TileTree::query_fast($zoom, $x, $y, $set_id);
|
||||
$rows = array();
|
||||
if ($rs !== null)
|
||||
{
|
||||
while ($row = mysql_fetch_row($rs))
|
||||
$rows[] = $row;
|
||||
unset($row);
|
||||
}
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointA", null,
|
||||
microtime(true) - $checkpointA_started);
|
||||
$checkpointB_started = microtime(true);
|
||||
|
||||
# Add dynamic, user-related flags.
|
||||
# Add dynamic, user-related flags.
|
||||
|
||||
if (count($rows) > 0)
|
||||
{
|
||||
# Load user-related cache ids.
|
||||
if (count($rows) > 0)
|
||||
{
|
||||
# Load user-related cache ids.
|
||||
|
||||
$cache_key = "tileuser/".$request->token->user_id;
|
||||
$user = self::$USE_OTHER_CACHE ? Cache::get($cache_key) : null;
|
||||
if ($user === null)
|
||||
{
|
||||
$user = array();
|
||||
$cache_key = "tileuser/".$request->token->user_id;
|
||||
$user = self::$USE_OTHER_CACHE ? Cache::get($cache_key) : null;
|
||||
if ($user === null)
|
||||
{
|
||||
$user = array();
|
||||
|
||||
# Ignored caches.
|
||||
# Ignored caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select cache_id
|
||||
from cache_ignore
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$user['ignored'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['ignored'][$cache_id] = true;
|
||||
$rs = Db::query("
|
||||
select cache_id
|
||||
from cache_ignore
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$user['ignored'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['ignored'][$cache_id] = true;
|
||||
|
||||
# Found caches.
|
||||
# Found caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from cache_logs
|
||||
where
|
||||
user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
and type = 1
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
");
|
||||
$user['found'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['found'][$cache_id] = true;
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from cache_logs
|
||||
where
|
||||
user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
and type = 1
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
");
|
||||
$user['found'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['found'][$cache_id] = true;
|
||||
|
||||
# Own caches.
|
||||
# Own caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from caches
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$user['own'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['own'][$cache_id] = true;
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from caches
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$user['own'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['own'][$cache_id] = true;
|
||||
|
||||
Cache::set($cache_key, $user, 30);
|
||||
}
|
||||
Cache::set($cache_key, $user, 30);
|
||||
}
|
||||
|
||||
# Add extra flags to geocaches.
|
||||
# Add extra flags to geocaches.
|
||||
|
||||
foreach ($rows as &$row_ref)
|
||||
{
|
||||
# Add the "found" flag (to indicate that this cache needs
|
||||
# to be drawn as found) and the "own" flag (to indicate that
|
||||
# the current user is the owner).
|
||||
foreach ($rows as &$row_ref)
|
||||
{
|
||||
# Add the "found" flag (to indicate that this cache needs
|
||||
# to be drawn as found) and the "own" flag (to indicate that
|
||||
# the current user is the owner).
|
||||
|
||||
if (isset($user['found'][$row_ref[0]]))
|
||||
$row_ref[6] |= TileTree::$FLAG_FOUND; # $row[6] is "flags"
|
||||
if (isset($user['own'][$row_ref[0]]))
|
||||
$row_ref[6] |= TileTree::$FLAG_OWN; # $row[6] is "flags"
|
||||
}
|
||||
}
|
||||
if (isset($user['found'][$row_ref[0]]))
|
||||
$row_ref[6] |= TileTree::$FLAG_FOUND; # $row[6] is "flags"
|
||||
if (isset($user['own'][$row_ref[0]]))
|
||||
$row_ref[6] |= TileTree::$FLAG_OWN; # $row[6] is "flags"
|
||||
}
|
||||
}
|
||||
|
||||
# Compute the image hash/fingerprint. This will be used both for ETags
|
||||
# and internal cache ($cache_key).
|
||||
# Compute the image hash/fingerprint. This will be used both for ETags
|
||||
# and internal cache ($cache_key).
|
||||
|
||||
$tile = new DefaultTileRenderer($zoom, $rows);
|
||||
$image_fingerprint = $tile->get_unique_hash();
|
||||
$tile = new DefaultTileRenderer($zoom, $rows);
|
||||
$image_fingerprint = $tile->get_unique_hash();
|
||||
|
||||
# Start creating response.
|
||||
# Start creating response.
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = $tile->get_content_type();
|
||||
$response->cache_control = "Cache-Control: private, max-age=600";
|
||||
$response->etag = 'W/"'.$image_fingerprint.'"';
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = $tile->get_content_type();
|
||||
$response->cache_control = "Cache-Control: private, max-age=600";
|
||||
$response->etag = 'W/"'.$image_fingerprint.'"';
|
||||
|
||||
# Check if the request didn't include the same ETag.
|
||||
# Check if the request didn't include the same ETag.
|
||||
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointB", null,
|
||||
microtime(true) - $checkpointB_started);
|
||||
$checkpointC_started = microtime(true);
|
||||
if (self::$USE_ETAGS_CACHE && ($request->etag == $response->etag))
|
||||
{
|
||||
# Hit. Report the content was unmodified.
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointB", null,
|
||||
microtime(true) - $checkpointB_started);
|
||||
$checkpointC_started = microtime(true);
|
||||
if (self::$USE_ETAGS_CACHE && ($request->etag == $response->etag))
|
||||
{
|
||||
# Hit. Report the content was unmodified.
|
||||
|
||||
$response->etag = null;
|
||||
$response->status = "304 Not Modified";
|
||||
return $response;
|
||||
}
|
||||
$response->etag = null;
|
||||
$response->status = "304 Not Modified";
|
||||
return $response;
|
||||
}
|
||||
|
||||
# Check if the image was recently rendered and is kept in image cache.
|
||||
# Check if the image was recently rendered and is kept in image cache.
|
||||
|
||||
$cache_key = "tile/".$image_fingerprint;
|
||||
$response->body = self::$USE_IMAGE_CACHE ? Cache::get($cache_key) : null;
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointC", null,
|
||||
microtime(true) - $checkpointC_started);
|
||||
$checkpointD_started = microtime(true);
|
||||
if ($response->body !== null)
|
||||
{
|
||||
# Hit. We will use the cached version of the image.
|
||||
$cache_key = "tile/".$image_fingerprint;
|
||||
$response->body = self::$USE_IMAGE_CACHE ? Cache::get($cache_key) : null;
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointC", null,
|
||||
microtime(true) - $checkpointC_started);
|
||||
$checkpointD_started = microtime(true);
|
||||
if ($response->body !== null)
|
||||
{
|
||||
# Hit. We will use the cached version of the image.
|
||||
|
||||
return $response;
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
# Miss. Render the image. Cache the result.
|
||||
# Miss. Render the image. Cache the result.
|
||||
|
||||
$response->body = $tile->render();
|
||||
Cache::set_scored($cache_key, $response->body);
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointD", null,
|
||||
microtime(true) - $checkpointD_started);
|
||||
$response->body = $tile->render();
|
||||
Cache::set_scored($cache_key, $response->body);
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointD", null,
|
||||
microtime(true) - $checkpointD_started);
|
||||
|
||||
return $response;
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
<xml>
|
||||
<brief>Get cache map tile</brief>
|
||||
<issue-id>150</issue-id>
|
||||
<desc>
|
||||
<p><b>CLOSED BETA</b> version. Due to long-term performance tests, currently
|
||||
this method is not publicly accessible. Let us know if you're interested
|
||||
in using it.</p>
|
||||
<p>Use this method to retrieve a tile-map of all caches included in your search
|
||||
result.</p>
|
||||
</desc>
|
||||
<req name='z'>Zoom level (0..21).</req>
|
||||
<req name='x'>Tile number on the X axis.</req>
|
||||
<req name='y'>Tile number on the Y axis.</req>
|
||||
<import-params method="services/caches/search/save"/>
|
||||
<returns>
|
||||
The PNG image with the requested map tile.
|
||||
</returns>
|
||||
<brief>Get cache map tile</brief>
|
||||
<issue-id>150</issue-id>
|
||||
<desc>
|
||||
<p><b>CLOSED BETA</b> version. Due to long-term performance tests, currently
|
||||
this method is not publicly accessible. Let us know if you're interested
|
||||
in using it.</p>
|
||||
<p>Use this method to retrieve a tile-map of all caches included in your search
|
||||
result.</p>
|
||||
</desc>
|
||||
<req name='z'>Zoom level (0..21).</req>
|
||||
<req name='x'>Tile number on the X axis.</req>
|
||||
<req name='y'>Tile number on the Y axis.</req>
|
||||
<import-params method="services/caches/search/save"/>
|
||||
<returns>
|
||||
The PNG image with the requested map tile.
|
||||
</returns>
|
||||
</xml>
|
File diff suppressed because it is too large
Load Diff
@ -21,274 +21,283 @@ use okapi\OkapiLock;
|
||||
|
||||
class TileTree
|
||||
{
|
||||
# Static flags (stored in the database).
|
||||
public static $FLAG_STAR = 0x01;
|
||||
public static $FLAG_HAS_TRACKABLES = 0x02;
|
||||
public static $FLAG_NOT_YET_FOUND = 0x04;
|
||||
# Static flags (stored in the database).
|
||||
public static $FLAG_STAR = 0x01;
|
||||
public static $FLAG_HAS_TRACKABLES = 0x02;
|
||||
public static $FLAG_NOT_YET_FOUND = 0x04;
|
||||
|
||||
# Dynamic flags (added at runtime).
|
||||
public static $FLAG_FOUND = 0x0100;
|
||||
public static $FLAG_OWN = 0x0200;
|
||||
public static $FLAG_NEW = 0x0400;
|
||||
public static $FLAG_DRAW_CAPTION = 0x0800;
|
||||
# Dynamic flags (added at runtime).
|
||||
public static $FLAG_FOUND = 0x0100;
|
||||
public static $FLAG_OWN = 0x0200;
|
||||
public static $FLAG_NEW = 0x0400;
|
||||
public static $FLAG_DRAW_CAPTION = 0x0800;
|
||||
|
||||
/**
|
||||
* Return null if not computed, 1 if computed and empty, 2 if computed and not empty.
|
||||
*/
|
||||
public static function get_tile_status($zoom, $x, $y)
|
||||
{
|
||||
return Db::select_value("
|
||||
select status
|
||||
from okapi_tile_status
|
||||
where
|
||||
z = '".mysql_real_escape_string($zoom)."'
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
");
|
||||
}
|
||||
/**
|
||||
* Return null if not computed, 1 if computed and empty, 2 if computed and not empty.
|
||||
*/
|
||||
public static function get_tile_status($zoom, $x, $y)
|
||||
{
|
||||
return Db::select_value("
|
||||
select status
|
||||
from okapi_tile_status
|
||||
where
|
||||
z = '".mysql_real_escape_string($zoom)."'
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return MySQL's result set iterator over all caches which are present
|
||||
* in the given result set AND in the given tile.
|
||||
*
|
||||
* Each row is an array of the following format:
|
||||
* list(cache_id, $pixel_x, $pixel_y, status, type, rating, flags, count).
|
||||
*
|
||||
* Note that $pixels can also be negative or >=256 (up to a margin of 32px).
|
||||
* Count is the number of other caches "eclipsed" by this geocache (such
|
||||
* eclipsed geocaches are not included in the result).
|
||||
*/
|
||||
public static function query_fast($zoom, $x, $y, $set_id)
|
||||
{
|
||||
# First, we check if the cache-set for this tile was already computed
|
||||
# (and if it was, was it empty).
|
||||
/**
|
||||
* Return MySQL's result set iterator over all caches which are present
|
||||
* in the given result set AND in the given tile.
|
||||
*
|
||||
* Each row is an array of the following format:
|
||||
* list(cache_id, $pixel_x, $pixel_y, status, type, rating, flags, count).
|
||||
*
|
||||
* Note that $pixels can also be negative or >=256 (up to a margin of 32px).
|
||||
* Count is the number of other caches "eclipsed" by this geocache (such
|
||||
* eclipsed geocaches are not included in the result).
|
||||
*/
|
||||
public static function query_fast($zoom, $x, $y, $set_id)
|
||||
{
|
||||
# First, we check if the cache-set for this tile was already computed
|
||||
# (and if it was, was it empty).
|
||||
|
||||
$status = self::get_tile_status($zoom, $x, $y);
|
||||
if ($status === null) # Not yet computed.
|
||||
{
|
||||
# Note, that computing the tile does not involve taking any
|
||||
# search parameters.
|
||||
$status = self::get_tile_status($zoom, $x, $y);
|
||||
if ($status === null) # Not yet computed.
|
||||
{
|
||||
# Note, that computing the tile does not involve taking any
|
||||
# search parameters.
|
||||
|
||||
$status = self::compute_tile($zoom, $x, $y);
|
||||
}
|
||||
$status = self::compute_tile($zoom, $x, $y);
|
||||
}
|
||||
|
||||
if ($status === 1) # Computed and empty.
|
||||
{
|
||||
# This tile was already computed and it is empty.
|
||||
return null;
|
||||
}
|
||||
if ($status === 1) # Computed and empty.
|
||||
{
|
||||
# This tile was already computed and it is empty.
|
||||
return null;
|
||||
}
|
||||
|
||||
# If we got here, then the tile is computed and not empty (status 2).
|
||||
# If we got here, then the tile is computed and not empty (status 2).
|
||||
|
||||
$tile_upper_x = $x << 8;
|
||||
$tile_leftmost_y = $y << 8;
|
||||
$tile_upper_x = $x << 8;
|
||||
$tile_leftmost_y = $y << 8;
|
||||
|
||||
$zoom_escaped = "'".mysql_real_escape_string($zoom)."'";
|
||||
$tile_upper_x_escaped = "'".mysql_real_escape_string($tile_upper_x)."'";
|
||||
$tile_leftmost_y_escaped = "'".mysql_real_escape_string($tile_leftmost_y)."'";
|
||||
return Db::query("
|
||||
select
|
||||
otc.cache_id,
|
||||
cast(otc.z21x >> (21 - $zoom_escaped) as signed) - $tile_upper_x_escaped as px,
|
||||
cast(otc.z21y >> (21 - $zoom_escaped) as signed) - $tile_leftmost_y_escaped as py,
|
||||
otc.status, otc.type, otc.rating, otc.flags, count(*)
|
||||
from
|
||||
okapi_tile_caches otc,
|
||||
okapi_search_results osr
|
||||
where
|
||||
z = $zoom_escaped
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
and otc.cache_id = osr.cache_id
|
||||
and osr.set_id = '".mysql_real_escape_string($set_id)."'
|
||||
group by
|
||||
z21x >> (3 + (21 - $zoom_escaped)),
|
||||
z21y >> (3 + (21 - $zoom_escaped))
|
||||
order by
|
||||
z21y >> (3 + (21 - $zoom_escaped)),
|
||||
z21x >> (3 + (21 - $zoom_escaped))
|
||||
");
|
||||
}
|
||||
$zoom_escaped = "'".mysql_real_escape_string($zoom)."'";
|
||||
$tile_upper_x_escaped = "'".mysql_real_escape_string($tile_upper_x)."'";
|
||||
$tile_leftmost_y_escaped = "'".mysql_real_escape_string($tile_leftmost_y)."'";
|
||||
return Db::query("
|
||||
select
|
||||
otc.cache_id,
|
||||
cast(otc.z21x >> (21 - $zoom_escaped) as signed) - $tile_upper_x_escaped as px,
|
||||
cast(otc.z21y >> (21 - $zoom_escaped) as signed) - $tile_leftmost_y_escaped as py,
|
||||
otc.status, otc.type, otc.rating, otc.flags, count(*)
|
||||
from
|
||||
okapi_tile_caches otc,
|
||||
okapi_search_results osr
|
||||
where
|
||||
z = $zoom_escaped
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
and otc.cache_id = osr.cache_id
|
||||
and osr.set_id = '".mysql_real_escape_string($set_id)."'
|
||||
group by
|
||||
z21x >> (3 + (21 - $zoom_escaped)),
|
||||
z21y >> (3 + (21 - $zoom_escaped))
|
||||
order by
|
||||
z21y >> (3 + (21 - $zoom_escaped)),
|
||||
z21x >> (3 + (21 - $zoom_escaped))
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Precache the ($zoom, $x, $y) slot in the okapi_tile_caches table.
|
||||
*/
|
||||
public static function compute_tile($zoom, $x, $y)
|
||||
{
|
||||
$time_started = microtime(true);
|
||||
/**
|
||||
* Precache the ($zoom, $x, $y) slot in the okapi_tile_caches table.
|
||||
*/
|
||||
public static function compute_tile($zoom, $x, $y)
|
||||
{
|
||||
$time_started = microtime(true);
|
||||
|
||||
# Note, that multiple threads may try to compute tiles simulatanously.
|
||||
# For low-level tiles, this can be expensive. WRTODO: Think of some
|
||||
# appropriate locks.
|
||||
# Note, that multiple threads may try to compute tiles simulatanously.
|
||||
# For low-level tiles, this can be expensive. WRTODO: Think of some
|
||||
# appropriate locks.
|
||||
|
||||
$status = self::get_tile_status($zoom, $x, $y);
|
||||
if ($status !== null)
|
||||
return $status;
|
||||
$status = self::get_tile_status($zoom, $x, $y);
|
||||
if ($status !== null)
|
||||
return $status;
|
||||
|
||||
if ($zoom === 0)
|
||||
{
|
||||
# When computing zoom zero, we don't have a parent to speed up
|
||||
# the computation. We need to use the caches table. Note, that
|
||||
# zoom level 0 contains *entire world*, so we don't have to use
|
||||
# any WHERE condition in the following query.
|
||||
if ($zoom === 0)
|
||||
{
|
||||
# When computing zoom zero, we don't have a parent to speed up
|
||||
# the computation. We need to use the caches table. Note, that
|
||||
# zoom level 0 contains *entire world*, so we don't have to use
|
||||
# any WHERE condition in the following query.
|
||||
|
||||
# This can be done a little faster (without the use of internal requests),
|
||||
# but there is *no need* to - this query is run seldom and is cached.
|
||||
# This can be done a little faster (without the use of internal requests),
|
||||
# but there is *no need* to - this query is run seldom and is cached.
|
||||
|
||||
$params = array();
|
||||
$params['status'] = "Available|Temporarily unavailable|Archived"; # we want them all
|
||||
$params['limit'] = "10000000"; # no limit
|
||||
$params = array();
|
||||
$params['status'] = "Available|Temporarily unavailable|Archived"; # we want them all
|
||||
$params['limit'] = "10000000"; # no limit
|
||||
|
||||
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, $params);
|
||||
$internal_request->skip_limits = true;
|
||||
$response = OkapiServiceRunner::call("services/caches/search/all", $internal_request);
|
||||
$cache_codes = $response['results'];
|
||||
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, $params);
|
||||
$internal_request->skip_limits = true;
|
||||
$response = OkapiServiceRunner::call("services/caches/search/all", $internal_request);
|
||||
$cache_codes = $response['results'];
|
||||
|
||||
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
||||
'cache_codes' => implode('|', $cache_codes),
|
||||
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
||||
));
|
||||
$internal_request->skip_limits = true;
|
||||
$caches = OkapiServiceRunner::call("services/caches/geocaches", $internal_request);
|
||||
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
||||
'cache_codes' => implode('|', $cache_codes),
|
||||
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
||||
));
|
||||
$internal_request->skip_limits = true;
|
||||
$caches = OkapiServiceRunner::call("services/caches/geocaches", $internal_request);
|
||||
|
||||
foreach ($caches as $cache)
|
||||
{
|
||||
$row = self::generate_short_row($cache);
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
) values (
|
||||
0, 0, 0,
|
||||
'".mysql_real_escape_string($row[0])."',
|
||||
'".mysql_real_escape_string($row[1])."',
|
||||
'".mysql_real_escape_string($row[2])."',
|
||||
'".mysql_real_escape_string($row[3])."',
|
||||
'".mysql_real_escape_string($row[4])."',
|
||||
".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").",
|
||||
'".mysql_real_escape_string($row[6])."'
|
||||
);
|
||||
");
|
||||
}
|
||||
$status = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
# We will use the parent tile to compute the contents of this tile.
|
||||
foreach ($caches as $cache)
|
||||
{
|
||||
$row = self::generate_short_row($cache);
|
||||
if (!$row) {
|
||||
/* Some caches cannot be included, e.g. the ones near the poles. */
|
||||
continue;
|
||||
}
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
) values (
|
||||
0, 0, 0,
|
||||
'".mysql_real_escape_string($row[0])."',
|
||||
'".mysql_real_escape_string($row[1])."',
|
||||
'".mysql_real_escape_string($row[2])."',
|
||||
'".mysql_real_escape_string($row[3])."',
|
||||
'".mysql_real_escape_string($row[4])."',
|
||||
".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").",
|
||||
'".mysql_real_escape_string($row[6])."'
|
||||
);
|
||||
");
|
||||
}
|
||||
$status = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
# We will use the parent tile to compute the contents of this tile.
|
||||
|
||||
$parent_zoom = $zoom - 1;
|
||||
$parent_x = $x >> 1;
|
||||
$parent_y = $y >> 1;
|
||||
$parent_zoom = $zoom - 1;
|
||||
$parent_x = $x >> 1;
|
||||
$parent_y = $y >> 1;
|
||||
|
||||
$status = self::get_tile_status($parent_zoom, $parent_x, $parent_y);
|
||||
if ($status === null) # Not computed.
|
||||
{
|
||||
$time_started = microtime(true);
|
||||
$status = self::compute_tile($parent_zoom, $parent_x, $parent_y);
|
||||
}
|
||||
$status = self::get_tile_status($parent_zoom, $parent_x, $parent_y);
|
||||
if ($status === null) # Not computed.
|
||||
{
|
||||
$time_started = microtime(true);
|
||||
$status = self::compute_tile($parent_zoom, $parent_x, $parent_y);
|
||||
}
|
||||
|
||||
if ($status === 1) # Computed and empty.
|
||||
{
|
||||
# No need to check.
|
||||
}
|
||||
else # Computed, not empty.
|
||||
{
|
||||
$scale = 8 + 21 - $zoom;
|
||||
$parentcenter_z21x = (($parent_x << 1) | 1) << $scale;
|
||||
$parentcenter_z21y = (($parent_y << 1) | 1) << $scale;
|
||||
$margin = 1 << ($scale - 2);
|
||||
$left_z21x = (($parent_x << 1) << $scale) - $margin;
|
||||
$right_z21x = ((($parent_x + 1) << 1) << $scale) + $margin;
|
||||
$top_z21y = (($parent_y << 1) << $scale) - $margin;
|
||||
$bottom_z21y = ((($parent_y + 1) << 1) << $scale) + $margin;
|
||||
if ($status === 1) # Computed and empty.
|
||||
{
|
||||
# No need to check.
|
||||
}
|
||||
else # Computed, not empty.
|
||||
{
|
||||
$scale = 8 + 21 - $zoom;
|
||||
$parentcenter_z21x = (($parent_x << 1) | 1) << $scale;
|
||||
$parentcenter_z21y = (($parent_y << 1) | 1) << $scale;
|
||||
$margin = 1 << ($scale - 2);
|
||||
$left_z21x = (($parent_x << 1) << $scale) - $margin;
|
||||
$right_z21x = ((($parent_x + 1) << 1) << $scale) + $margin;
|
||||
$top_z21y = (($parent_y << 1) << $scale) - $margin;
|
||||
$bottom_z21y = ((($parent_y + 1) << 1) << $scale) + $margin;
|
||||
|
||||
# Choose the right quarter.
|
||||
# |1 2|
|
||||
# |3 4|
|
||||
# Choose the right quarter.
|
||||
# |1 2|
|
||||
# |3 4|
|
||||
|
||||
if ($x & 1) # 2 or 4
|
||||
$left_z21x = $parentcenter_z21x - $margin;
|
||||
else # 1 or 3
|
||||
$right_z21x = $parentcenter_z21x + $margin;
|
||||
if ($y & 1) # 3 or 4
|
||||
$top_z21y = $parentcenter_z21y - $margin;
|
||||
else # 1 or 2
|
||||
$bottom_z21y = $parentcenter_z21y + $margin;
|
||||
if ($x & 1) # 2 or 4
|
||||
$left_z21x = $parentcenter_z21x - $margin;
|
||||
else # 1 or 3
|
||||
$right_z21x = $parentcenter_z21x + $margin;
|
||||
if ($y & 1) # 3 or 4
|
||||
$top_z21y = $parentcenter_z21y - $margin;
|
||||
else # 1 or 2
|
||||
$bottom_z21y = $parentcenter_z21y + $margin;
|
||||
|
||||
# Cache the result.
|
||||
# Cache the result.
|
||||
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
)
|
||||
select
|
||||
'".mysql_real_escape_string($zoom)."',
|
||||
'".mysql_real_escape_string($x)."',
|
||||
'".mysql_real_escape_string($y)."',
|
||||
cache_id, z21x, z21y, status, type, rating, flags
|
||||
from okapi_tile_caches
|
||||
where
|
||||
z = '".mysql_real_escape_string($parent_zoom)."'
|
||||
and x = '".mysql_real_escape_string($parent_x)."'
|
||||
and y = '".mysql_real_escape_string($parent_y)."'
|
||||
and z21x between $left_z21x and $right_z21x
|
||||
and z21y between $top_z21y and $bottom_z21y
|
||||
");
|
||||
$test = Db::select_value("
|
||||
select 1
|
||||
from okapi_tile_caches
|
||||
where
|
||||
z = '".mysql_real_escape_string($zoom)."'
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
limit 1;
|
||||
");
|
||||
if ($test)
|
||||
$status = 2;
|
||||
else
|
||||
$status = 1;
|
||||
}
|
||||
}
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
)
|
||||
select
|
||||
'".mysql_real_escape_string($zoom)."',
|
||||
'".mysql_real_escape_string($x)."',
|
||||
'".mysql_real_escape_string($y)."',
|
||||
cache_id, z21x, z21y, status, type, rating, flags
|
||||
from okapi_tile_caches
|
||||
where
|
||||
z = '".mysql_real_escape_string($parent_zoom)."'
|
||||
and x = '".mysql_real_escape_string($parent_x)."'
|
||||
and y = '".mysql_real_escape_string($parent_y)."'
|
||||
and z21x between $left_z21x and $right_z21x
|
||||
and z21y between $top_z21y and $bottom_z21y
|
||||
");
|
||||
$test = Db::select_value("
|
||||
select 1
|
||||
from okapi_tile_caches
|
||||
where
|
||||
z = '".mysql_real_escape_string($zoom)."'
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
limit 1;
|
||||
");
|
||||
if ($test)
|
||||
$status = 2;
|
||||
else
|
||||
$status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Mark tile as computed.
|
||||
# Mark tile as computed.
|
||||
|
||||
Db::execute("
|
||||
replace into okapi_tile_status (z, x, y, status)
|
||||
values (
|
||||
'".mysql_real_escape_string($zoom)."',
|
||||
'".mysql_real_escape_string($x)."',
|
||||
'".mysql_real_escape_string($y)."',
|
||||
'".mysql_real_escape_string($status)."'
|
||||
);
|
||||
");
|
||||
Db::execute("
|
||||
replace into okapi_tile_status (z, x, y, status)
|
||||
values (
|
||||
'".mysql_real_escape_string($zoom)."',
|
||||
'".mysql_real_escape_string($x)."',
|
||||
'".mysql_real_escape_string($y)."',
|
||||
'".mysql_real_escape_string($status)."'
|
||||
);
|
||||
");
|
||||
|
||||
return $status;
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert OKAPI's cache object to a short database row to be inserted
|
||||
* into okapi_tile_caches table. Returns the list of the following attributes:
|
||||
* cache_id, z21x, z21y, status, type, rating, flags (rating might be null!).
|
||||
*/
|
||||
public static function generate_short_row($cache)
|
||||
{
|
||||
list($lat, $lon) = explode("|", $cache['location']);
|
||||
list($z21x, $z21y) = self::latlon_to_z21xy($lat, $lon);
|
||||
$flags = 0;
|
||||
if (($cache['founds'] > 6) && (($cache['recommendations'] / $cache['founds']) > 0.3))
|
||||
$flags |= self::$FLAG_STAR;
|
||||
if ($cache['trackables_count'] > 0)
|
||||
$flags |= self::$FLAG_HAS_TRACKABLES;
|
||||
if ($cache['founds'] == 0)
|
||||
$flags |= self::$FLAG_NOT_YET_FOUND;
|
||||
return array($cache['internal_id'], $z21x, $z21y, Okapi::cache_status_name2id($cache['status']),
|
||||
Okapi::cache_type_name2id($cache['type']), $cache['rating'], $flags);
|
||||
}
|
||||
/**
|
||||
* Convert OKAPI's cache object to a short database row to be inserted
|
||||
* into okapi_tile_caches table. Returns the list of the following attributes:
|
||||
* cache_id, z21x, z21y, status, type, rating, flags (rating might be null!).
|
||||
*/
|
||||
public static function generate_short_row($cache)
|
||||
{
|
||||
list($lat, $lon) = explode("|", $cache['location']);
|
||||
try {
|
||||
list($z21x, $z21y) = self::latlon_to_z21xy($lat, $lon);
|
||||
} catch (Exception $e) {
|
||||
/* E.g. division by zero, if the cache is placed at the north pole. */
|
||||
return false;
|
||||
}
|
||||
$flags = 0;
|
||||
if (($cache['founds'] > 6) && (($cache['recommendations'] / $cache['founds']) > 0.3))
|
||||
$flags |= self::$FLAG_STAR;
|
||||
if ($cache['trackables_count'] > 0)
|
||||
$flags |= self::$FLAG_HAS_TRACKABLES;
|
||||
if ($cache['founds'] == 0)
|
||||
$flags |= self::$FLAG_NOT_YET_FOUND;
|
||||
return array($cache['internal_id'], $z21x, $z21y, Okapi::cache_status_name2id($cache['status']),
|
||||
Okapi::cache_type_name2id($cache['type']), $cache['rating'], $flags);
|
||||
}
|
||||
|
||||
private static function latlon_to_z21xy($lat, $lon)
|
||||
{
|
||||
$offset = 128 << 21;
|
||||
$x = round($offset + ($offset * $lon / 180));
|
||||
$y = round($offset - $offset/pi() * log((1 + sin($lat * pi() / 180)) / (1 - sin($lat * pi() / 180))) / 2);
|
||||
return array($x, $y);
|
||||
}
|
||||
private static function latlon_to_z21xy($lat, $lon)
|
||||
{
|
||||
$offset = 128 << 21;
|
||||
$x = round($offset + ($offset * $lon / 180));
|
||||
$y = round($offset - $offset/pi() * log((1 + sin($lat * pi() / 180)) / (1 - sin($lat * pi() / 180))) / 2);
|
||||
return array($x, $y);
|
||||
}
|
||||
}
|
@ -17,74 +17,74 @@ use okapi\Settings;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 3
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 3
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# User is already verified (via OAuth), but we need to verify the
|
||||
# cache code (check if it exists). We will simply call a geocache method
|
||||
# on it - this will also throw a proper exception if it doesn't exist.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# User is already verified (via OAuth), but we need to verify the
|
||||
# cache code (check if it exists). We will simply call a geocache method
|
||||
# on it - this will also throw a proper exception if it doesn't exist.
|
||||
|
||||
$cache_code = $request->get_parameter('cache_code');
|
||||
if ($cache_code == null)
|
||||
throw new ParamMissing('cache_code');
|
||||
$geocache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
||||
$cache_code = $request->get_parameter('cache_code');
|
||||
if ($cache_code == null)
|
||||
throw new ParamMissing('cache_code');
|
||||
$geocache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
||||
|
||||
# watched
|
||||
# watched
|
||||
|
||||
if ($tmp = $request->get_parameter('watched'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
||||
throw new InvalidParam('watched', $tmp);
|
||||
if ($tmp == 'true')
|
||||
Db::execute("
|
||||
insert ignore into cache_watches (cache_id, user_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($geocache['internal_id'])."',
|
||||
'".mysql_real_escape_string($request->token->user_id)."'
|
||||
);
|
||||
");
|
||||
elseif ($tmp == 'false')
|
||||
Db::execute("
|
||||
delete from cache_watches
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
||||
and user_id = '".mysql_real_escape_string($request->token->user_id)."';
|
||||
");
|
||||
}
|
||||
if ($tmp = $request->get_parameter('watched'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
||||
throw new InvalidParam('watched', $tmp);
|
||||
if ($tmp == 'true')
|
||||
Db::execute("
|
||||
insert ignore into cache_watches (cache_id, user_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($geocache['internal_id'])."',
|
||||
'".mysql_real_escape_string($request->token->user_id)."'
|
||||
);
|
||||
");
|
||||
elseif ($tmp == 'false')
|
||||
Db::execute("
|
||||
delete from cache_watches
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
||||
and user_id = '".mysql_real_escape_string($request->token->user_id)."';
|
||||
");
|
||||
}
|
||||
|
||||
# ignored
|
||||
# ignored
|
||||
|
||||
if ($tmp = $request->get_parameter('ignored'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
||||
throw new InvalidParam('ignored', $tmp);
|
||||
if ($tmp == 'true')
|
||||
Db::execute("
|
||||
insert ignore into cache_ignore (cache_id, user_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($geocache['internal_id'])."',
|
||||
'".mysql_real_escape_string($request->token->user_id)."'
|
||||
);
|
||||
");
|
||||
elseif ($tmp == 'false')
|
||||
Db::execute("
|
||||
delete from cache_ignore
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
||||
and user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
}
|
||||
if ($tmp = $request->get_parameter('ignored'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
||||
throw new InvalidParam('ignored', $tmp);
|
||||
if ($tmp == 'true')
|
||||
Db::execute("
|
||||
insert ignore into cache_ignore (cache_id, user_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($geocache['internal_id'])."',
|
||||
'".mysql_real_escape_string($request->token->user_id)."'
|
||||
);
|
||||
");
|
||||
elseif ($tmp == 'false')
|
||||
Db::execute("
|
||||
delete from cache_ignore
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
||||
and user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'success' => true,
|
||||
);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$result = array(
|
||||
'success' => true,
|
||||
);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,33 @@
|
||||
<xml>
|
||||
<brief>Mark cache as watched or ignored</brief>
|
||||
<issue-id>166</issue-id>
|
||||
<desc>
|
||||
<p>This method allows your users to mark the geocache as <b>watched</b> or
|
||||
<b>ignored</b>.
|
||||
Read the docs on separate parameters for details.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>
|
||||
<p>Code of the geocache.</p>
|
||||
</req>
|
||||
<opt name='watched' default='unchanged'>
|
||||
<p>Mark (or unmark) the cache as watched. This should be <b>true</b>,
|
||||
<b>false</b> or <b>unchanged</b>. You may access the current state of this
|
||||
flag with the <b>is_watched</b> field of the geocache method.</p>
|
||||
</opt>
|
||||
<opt name='ignored' default='unchanged'>
|
||||
<p>Mark (or unmark) the cache as ignored. This should be <b>true</b>,
|
||||
<b>false</b> or <b>unchanged</b>. You may access the current state of this
|
||||
flag with the <b>is_ignored</b> field of the geocache method.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>success</b> - true, if all went well.</li>
|
||||
</ul>
|
||||
<p>Please note, that currently this will <b>always</b> be true! Nothing can go
|
||||
wrong as long as you pass your parameters in a right way (and if you don't,
|
||||
you will get an HTTP 400 response). If you have received an HTTP 200 response,
|
||||
then you may assume that all went well.</p>
|
||||
</returns>
|
||||
<brief>Mark cache as watched or ignored</brief>
|
||||
<issue-id>166</issue-id>
|
||||
<desc>
|
||||
<p>This method allows your users to mark the geocache as <b>watched</b> or
|
||||
<b>ignored</b>.
|
||||
Read the docs on separate parameters for details.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>
|
||||
<p>Code of the geocache.</p>
|
||||
</req>
|
||||
<opt name='watched' default='unchanged'>
|
||||
<p>Mark (or unmark) the cache as watched. This should be <b>true</b>,
|
||||
<b>false</b> or <b>unchanged</b>. You may access the current state of this
|
||||
flag with the <b>is_watched</b> field of the geocache method.</p>
|
||||
</opt>
|
||||
<opt name='ignored' default='unchanged'>
|
||||
<p>Mark (or unmark) the cache as ignored. This should be <b>true</b>,
|
||||
<b>false</b> or <b>unchanged</b>. You may access the current state of this
|
||||
flag with the <b>is_ignored</b> field of the geocache method.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>success</b> - true, if all went well.</li>
|
||||
</ul>
|
||||
<p>Please note, that currently this will <b>always</b> be true! Nothing can go
|
||||
wrong as long as you pass your parameters in a right way (and if you don't,
|
||||
you will get an HTTP 400 response). If you have received an HTTP 200 response,
|
||||
then you may assume that all went well.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -20,17 +20,18 @@ require_once('searching.inc.php');
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$search_params = SearchAssistant::get_common_search_params($request);
|
||||
$result = SearchAssistant::get_common_search_result($search_params);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$search_assistant = new SearchAssistant($request);
|
||||
$search_assistant->prepare_common_search_params();
|
||||
$result = $search_assistant->get_common_search_result();
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,209 +1,209 @@
|
||||
<xml>
|
||||
<brief>Search for geocaches</brief>
|
||||
<issue-id>15</issue-id>
|
||||
<desc>
|
||||
<p>Search for geocaches using some simple filters.
|
||||
All of them are optional, but you surely want to use at least some of them.</p>
|
||||
<ul>
|
||||
<li>If you're looking for a way to keep your geocaching database in sync with ours,
|
||||
have a peek at the <b>replicate</b> module.</li>
|
||||
<li>Usually you will want to use search_and_retrieve method instead of this one.
|
||||
This way, you can get much more data in <b>one request</b>.</li>
|
||||
</ul>
|
||||
</desc>
|
||||
<opt name='type'>
|
||||
<p>Pipe-separated list of cache type codes. If given, the results will be limited
|
||||
to the given cache types. For a list of cache type codes, see services/caches/geocache
|
||||
method.</p>
|
||||
<p><b>Notice:</b> If you want to include all cache types <b>except</b>
|
||||
given ones, prepend your list with the "-" sign.</p>
|
||||
</opt>
|
||||
<opt name='status' default='Available'>
|
||||
<p>Pipe-separated list of status codes. Only caches matching any of the given
|
||||
statuses will included in the response. For a list of cache status codes, see
|
||||
services/caches/geocache method.</p>
|
||||
</opt>
|
||||
<opt name='owner_uuid'>
|
||||
<p>Pipe-separated list of user IDs. If given, the list of returned caches
|
||||
will be limited to those owned by the given users.</p>
|
||||
<p><b>Notice:</b> User ID and Username are two different things!</p>
|
||||
<p><b>Notice:</b> If you want to include all caches <b>except</b> the ones
|
||||
owned by the given users, prepend your list with the "-" sign.</p>
|
||||
</opt>
|
||||
<opt name='name'>
|
||||
<p>UTF-8 encoded string - the name (or part of the name) of the cache.</p>
|
||||
<p>Allowed wildcard characters:</p>
|
||||
<ul>
|
||||
<li>asterisk ("*") will match any string of characters,</li>
|
||||
<li>underscore ("_") will match any single character.</li>
|
||||
</ul>
|
||||
<p>Name matching is case-insensitive. Maximum length for the <b>name</b> parameter
|
||||
is 100 characters.</p>
|
||||
<p><b>Examples:</b></p>
|
||||
<ul>
|
||||
<li>"name=the *" returns caches which name starts with "the " (or "The ", etc.),</li>
|
||||
<li>"name=water tower" returns caches which have <b>exactly</b> that name (case insensitive),</li>
|
||||
<li>"name=*water tower*" will match caches like "Beautiful Water Tower II",</li>
|
||||
<li>"name=*tower_" will match "Water Towers" but will <b>not</b> match "Water Tower".</li>
|
||||
</ul>
|
||||
<p><b>Notice:</b> Cache code and name are two different things - if you want to
|
||||
find a cache by its code, use the services/caches/geocache method.</p>
|
||||
</opt>
|
||||
<opt name='terrain' default='1-5'>
|
||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
||||
Only caches with terrain rating between these numbers (inclusive) will be returned.</p>
|
||||
</opt>
|
||||
<opt name='difficulty' default='1-5'>
|
||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
||||
Only caches with difficulty rating between these numbers (inclusive) will be returned.</p>
|
||||
</opt>
|
||||
<opt name='size' class='deprecated'>
|
||||
<p>Deprecated. Please use <b>size2</b> instead - this will allow you to
|
||||
differentiate "nano" vs. "micro" and "none" vs. "other" sizes
|
||||
(<a href='http://code.google.com/p/opencaching-api/issues/detail?id=155'>details</a>).</p>
|
||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
||||
Only caches with size attribute between these numbers (inclusive) will be returned
|
||||
(1 - micro, 5 - very big).</p>
|
||||
<p><b>Notice:</b> If you use this parameter, all caches which do not have a container
|
||||
(like Event or Virtual caches) will be excluded from the results. If you want caches
|
||||
with no container included, append "|X" suffix to the value of this parameter
|
||||
(e.g. "3-5|X").</p>
|
||||
</opt>
|
||||
<opt name='size2'>
|
||||
<p>Pipe-separated list of "size2 codes". Only matching caches will be
|
||||
included. The codes are: 'none', 'nano', 'micro', 'small', 'regular',
|
||||
'large', 'xlarge', 'other'.</p>
|
||||
<p><b>Note:</b> Not all OC servers use all of these. I.e. OCPL does not
|
||||
have 'nano' nor 'other' caches (but it might have them in the future).</p>
|
||||
</opt>
|
||||
<opt name='rating'>
|
||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
||||
Only caches with an overall rating between these numbers (inclusive) will be returned
|
||||
(1 - poor, 5 - excellent).</p>
|
||||
<p><b>Notice:</b> If you use this parameter, all caches with too few votes will be
|
||||
excluded from results. If you still want unrated caches included, append "|X" suffix
|
||||
to the value of this parameter (e.g. "3-5|X").</p>
|
||||
<p><b>Notice:</b> Some OC installations do not provide ratings for their geocaches.
|
||||
On such installation, this parameter will be ignored.</p>
|
||||
</opt>
|
||||
<opt name='min_rcmds'>
|
||||
<p>There are two possible value-types for this argument:</p>
|
||||
<ul>
|
||||
<li>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
||||
at least <i>N</i> recommendations.</li>
|
||||
<li>Integer N with a percent sign appended (e.g. "20%"). The result will contain
|
||||
only those caches which have at last <i>N%</i> ratio of recommendations/founds.
|
||||
Please note, that this is useful only with conjunction with <b>min_founds</b>
|
||||
parameter.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name='min_founds'>
|
||||
<p>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
||||
been found at least <i>N</i> times. Useful if you want to skip "unverified" caches.</p>
|
||||
</opt>
|
||||
<opt name='max_founds'>
|
||||
<p>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
||||
been found at most <i>N</i> times. Useful for FTF hunters.</p>
|
||||
</opt>
|
||||
<opt name='modified_since'>
|
||||
<p>A date and time string. This should be in ISO 8601 format (currently any
|
||||
format acceptable by PHP's <a href='http://pl2.php.net/strtotime'>strtotime</a>
|
||||
function also will do, but most of them don't handle time zones properly,
|
||||
try to use ISO 8601!).</p>
|
||||
<p>If given, the list of returned geocaches will be limited to those which were
|
||||
created or modified since that date. (Note: currently caches do not get
|
||||
"modified" when user makes a log entry.)</p>
|
||||
</opt>
|
||||
<opt name='found_status' default='either'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed with an Access Token
|
||||
(you will need to use <b>Level 3</b> Authentication).</p>
|
||||
<p>Should be one of the following:</p>
|
||||
<ul>
|
||||
<li><b>found_only</b> - only caches found by the user will be returned,</li>
|
||||
<li><b>notfound_only</b> - only caches <b>not</b> found by the user will be returned,</li>
|
||||
<li><b>either</b> - all caches will be returned.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name='found_by'>
|
||||
<p>User UUID. If given, the response will only include geocaches found by
|
||||
the given user.</p>
|
||||
</opt>
|
||||
<opt name='not_found_by'>
|
||||
<p>User UUID. If given, the response will only include geocaches not found by
|
||||
the given user.</p>
|
||||
</opt>
|
||||
<opt name='watched_only' default='false'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed with an Access Token
|
||||
(you will need to use <b>Level 3</b> Authentication).</p>
|
||||
<p>Boolean. If set to <b>true</b>, only caches which the user has marked as watched
|
||||
will be included in the result. This might be used to temporarily mark geocaches
|
||||
of particular interest (e.g. "all the caches I plan to find today").</p>
|
||||
</opt>
|
||||
<opt name='exclude_ignored' default='false'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed
|
||||
with an Access Token (you will need to use <b>Level 3</b> Authentication).</p>
|
||||
<p>Boolean. If set to <b>true</b>, caches which the user has marked as ignored
|
||||
will not be included in the result.</p>
|
||||
</opt>
|
||||
<opt name='exclude_my_own' default='false'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed
|
||||
with an Access Token (you will need to use <b>Level 3</b> Authentication).
|
||||
See <b>owner_uuid</b> parameter if you don't want to use OAuth.</p>
|
||||
<p>Boolean. If set to <b>true</b>, caches which the user is an owner of will
|
||||
not be included in the result.</p>
|
||||
</opt>
|
||||
<opt name='with_trackables_only' default='false'>
|
||||
Boolean. If set to <b>true</b>, only caches with at least one trackable
|
||||
will be included in the result.
|
||||
</opt>
|
||||
<opt name='ftf_hunter' default='false'>
|
||||
Boolean. If set to <b>true</b>, only caches which have not yet been
|
||||
found <b>by anyone</b> will be included.
|
||||
</opt>
|
||||
<opt name='set_and'>
|
||||
<p>ID of a set previously created with the <b>search/save</b> method.
|
||||
If given, the results are <a href='http://en.wikipedia.org/wiki/Logical_conjunction'>AND</a>ed
|
||||
together with this set.</p>
|
||||
<p>If you want to list the set contents only, please note the default
|
||||
value of the <b>status</b> parameter! You may want to override it
|
||||
in order to include unavailable and/or archived geocaches within the set.</p>
|
||||
</opt>
|
||||
<opt name='limit' default='100'>
|
||||
<p>Integer in range 1..500. Maximum number of cache codes returned.</p>
|
||||
</opt>
|
||||
<opt name='offset' default='0'>
|
||||
<p>An offset, the amount of items to skip at the beginning of the result. Combined with limit
|
||||
allows pagination of the result set. Please note, that the sum of offset and limit still cannot
|
||||
exceed 500. You MAY NOT use this method to list all the caches, it is for searching only.
|
||||
Have a peek at the <b>replicate</b> module if you need all the caches.</p>
|
||||
</opt>
|
||||
<opt name='order_by'>
|
||||
<p>Pipe separated list of fields to order the results by. Prefix the field name with
|
||||
a '-' sign to indicate a descending order.</p>
|
||||
<p>Currently, fields which you can order by include: <b>code</b>, <b>name</b>,
|
||||
<b>founds</b>, <b>rcmds</b>, <b>rcmds%</b> (tell us if you want more).</p>
|
||||
<p><b>Examples:</b></p>
|
||||
<ul>
|
||||
<li>to order by cache name use "order_by=name" or "order_by=+name",</li>
|
||||
<li>to have the most recommended caches caches in front, use "order_by=-rcmds%",</li>
|
||||
<li>multicolumn sorting is also allowed, ex. "order_by=-founds|name"</li>
|
||||
</ul>
|
||||
<p><b>Note:</b> Try to avoid executing separate OKAPI request every time you
|
||||
want to sort the data which you <b>already have</b>. Consider caching and
|
||||
sorting on client side. This will speed up things for both sides.</p>
|
||||
<p><b>Note:</b> For most other methods (like <b>bbox</b> and <b>nearest</b>),
|
||||
the default order is <i>by the distance from the center</i>. If you supply
|
||||
custom <b>order_by</b> parameter, then we will try to order by your preference
|
||||
first, and then by the distance later.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>results</b> - a list of cache codes,</li>
|
||||
<li><b>more</b> - boolean, <b>true</b> means that there were more
|
||||
results for your query, but they were not returned because of the
|
||||
<b>limit</b> parameter.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Search for geocaches</brief>
|
||||
<issue-id>15</issue-id>
|
||||
<desc>
|
||||
<p>Search for geocaches using some simple filters.
|
||||
All of them are optional, but you surely want to use at least some of them.</p>
|
||||
<ul>
|
||||
<li>If you're looking for a way to keep your geocaching database in sync with ours,
|
||||
have a peek at the <b>replicate</b> module.</li>
|
||||
<li>Usually you will want to use search_and_retrieve method instead of this one.
|
||||
This way, you can get much more data in <b>one request</b>.</li>
|
||||
</ul>
|
||||
</desc>
|
||||
<opt name='type'>
|
||||
<p>Pipe-separated list of cache type codes. If given, the results will be limited
|
||||
to the given cache types. For a list of cache type codes, see services/caches/geocache
|
||||
method.</p>
|
||||
<p><b>Notice:</b> If you want to include all cache types <b>except</b>
|
||||
given ones, prepend your list with the "-" sign.</p>
|
||||
</opt>
|
||||
<opt name='status' default='Available'>
|
||||
<p>Pipe-separated list of status codes. Only caches matching any of the given
|
||||
statuses will included in the response. For a list of cache status codes, see
|
||||
services/caches/geocache method.</p>
|
||||
</opt>
|
||||
<opt name='owner_uuid'>
|
||||
<p>Pipe-separated list of user IDs. If given, the list of returned caches
|
||||
will be limited to those owned by the given users.</p>
|
||||
<p><b>Notice:</b> User ID and Username are two different things!</p>
|
||||
<p><b>Notice:</b> If you want to include all caches <b>except</b> the ones
|
||||
owned by the given users, prepend your list with the "-" sign.</p>
|
||||
</opt>
|
||||
<opt name='name'>
|
||||
<p>UTF-8 encoded string - the name (or part of the name) of the cache.</p>
|
||||
<p>Allowed wildcard characters:</p>
|
||||
<ul>
|
||||
<li>asterisk ("*") will match any string of characters,</li>
|
||||
<li>underscore ("_") will match any single character.</li>
|
||||
</ul>
|
||||
<p>Name matching is case-insensitive. Maximum length for the <b>name</b> parameter
|
||||
is 100 characters.</p>
|
||||
<p><b>Examples:</b></p>
|
||||
<ul>
|
||||
<li>"name=the *" returns caches which name starts with "the " (or "The ", etc.),</li>
|
||||
<li>"name=water tower" returns caches which have <b>exactly</b> that name (case insensitive),</li>
|
||||
<li>"name=*water tower*" will match caches like "Beautiful Water Tower II",</li>
|
||||
<li>"name=*tower_" will match "Water Towers" but will <b>not</b> match "Water Tower".</li>
|
||||
</ul>
|
||||
<p><b>Notice:</b> Cache code and name are two different things - if you want to
|
||||
find a cache by its code, use the services/caches/geocache method.</p>
|
||||
</opt>
|
||||
<opt name='terrain' default='1-5'>
|
||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
||||
Only caches with terrain rating between these numbers (inclusive) will be returned.</p>
|
||||
</opt>
|
||||
<opt name='difficulty' default='1-5'>
|
||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
||||
Only caches with difficulty rating between these numbers (inclusive) will be returned.</p>
|
||||
</opt>
|
||||
<opt name='size' class='deprecated'>
|
||||
<p>Deprecated. Please use <b>size2</b> instead - this will allow you to
|
||||
differentiate "nano" vs. "micro" and "none" vs. "other" sizes
|
||||
(<a href='http://code.google.com/p/opencaching-api/issues/detail?id=155'>details</a>).</p>
|
||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
||||
Only caches with size attribute between these numbers (inclusive) will be returned
|
||||
(1 - micro, 5 - very big).</p>
|
||||
<p><b>Notice:</b> If you use this parameter, all caches which do not have a container
|
||||
(like Event or Virtual caches) will be excluded from the results. If you want caches
|
||||
with no container included, append "|X" suffix to the value of this parameter
|
||||
(e.g. "3-5|X").</p>
|
||||
</opt>
|
||||
<opt name='size2'>
|
||||
<p>Pipe-separated list of "size2 codes". Only matching caches will be
|
||||
included. The codes are: 'none', 'nano', 'micro', 'small', 'regular',
|
||||
'large', 'xlarge', 'other'.</p>
|
||||
<p><b>Note:</b> Not all OC servers use all of these. I.e. OCPL does not
|
||||
have 'nano' nor 'other' caches (but it might have them in the future).</p>
|
||||
</opt>
|
||||
<opt name='rating'>
|
||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
||||
Only caches with an overall rating between these numbers (inclusive) will be returned
|
||||
(1 - poor, 5 - excellent).</p>
|
||||
<p><b>Notice:</b> If you use this parameter, all caches with too few votes will be
|
||||
excluded from results. If you still want unrated caches included, append "|X" suffix
|
||||
to the value of this parameter (e.g. "3-5|X").</p>
|
||||
<p><b>Notice:</b> Some OC installations do not provide ratings for their geocaches.
|
||||
On such installation, this parameter will be ignored.</p>
|
||||
</opt>
|
||||
<opt name='min_rcmds'>
|
||||
<p>There are two possible value-types for this argument:</p>
|
||||
<ul>
|
||||
<li>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
||||
at least <i>N</i> recommendations.</li>
|
||||
<li>Integer N with a percent sign appended (e.g. "20%"). The result will contain
|
||||
only those caches which have at last <i>N%</i> ratio of recommendations/founds.
|
||||
Please note, that this is useful only with conjunction with <b>min_founds</b>
|
||||
parameter.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name='min_founds'>
|
||||
<p>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
||||
been found at least <i>N</i> times. Useful if you want to skip "unverified" caches.</p>
|
||||
</opt>
|
||||
<opt name='max_founds'>
|
||||
<p>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
||||
been found at most <i>N</i> times. Useful for FTF hunters.</p>
|
||||
</opt>
|
||||
<opt name='modified_since'>
|
||||
<p>A date and time string. This should be in ISO 8601 format (currently any
|
||||
format acceptable by PHP's <a href='http://pl2.php.net/strtotime'>strtotime</a>
|
||||
function also will do, but most of them don't handle time zones properly,
|
||||
try to use ISO 8601!).</p>
|
||||
<p>If given, the list of returned geocaches will be limited to those which were
|
||||
created or modified since that date. (Note: currently caches do not get
|
||||
"modified" when user makes a log entry.)</p>
|
||||
</opt>
|
||||
<opt name='found_status' default='either'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed with an Access Token
|
||||
(you will need to use <b>Level 3</b> Authentication).</p>
|
||||
<p>Should be one of the following:</p>
|
||||
<ul>
|
||||
<li><b>found_only</b> - only caches found by the user will be returned,</li>
|
||||
<li><b>notfound_only</b> - only caches <b>not</b> found by the user will be returned,</li>
|
||||
<li><b>either</b> - all caches will be returned.</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name='found_by'>
|
||||
<p>User UUID. If given, the response will only include geocaches found by
|
||||
the given user.</p>
|
||||
</opt>
|
||||
<opt name='not_found_by'>
|
||||
<p>User UUID. If given, the response will only include geocaches not found by
|
||||
the given user.</p>
|
||||
</opt>
|
||||
<opt name='watched_only' default='false'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed with an Access Token
|
||||
(you will need to use <b>Level 3</b> Authentication).</p>
|
||||
<p>Boolean. If set to <b>true</b>, only caches which the user has marked as watched
|
||||
will be included in the result. This might be used to temporarily mark geocaches
|
||||
of particular interest (e.g. "all the caches I plan to find today").</p>
|
||||
</opt>
|
||||
<opt name='exclude_ignored' default='false'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed
|
||||
with an Access Token (you will need to use <b>Level 3</b> Authentication).</p>
|
||||
<p>Boolean. If set to <b>true</b>, caches which the user has marked as ignored
|
||||
will not be included in the result.</p>
|
||||
</opt>
|
||||
<opt name='exclude_my_own' default='false'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed
|
||||
with an Access Token (you will need to use <b>Level 3</b> Authentication).
|
||||
See <b>owner_uuid</b> parameter if you don't want to use OAuth.</p>
|
||||
<p>Boolean. If set to <b>true</b>, caches which the user is an owner of will
|
||||
not be included in the result.</p>
|
||||
</opt>
|
||||
<opt name='with_trackables_only' default='false'>
|
||||
Boolean. If set to <b>true</b>, only caches with at least one trackable
|
||||
will be included in the result.
|
||||
</opt>
|
||||
<opt name='ftf_hunter' default='false'>
|
||||
Boolean. If set to <b>true</b>, only caches which have not yet been
|
||||
found <b>by anyone</b> will be included.
|
||||
</opt>
|
||||
<opt name='set_and'>
|
||||
<p>ID of a set previously created with the <b>search/save</b> method.
|
||||
If given, the results are <a href='http://en.wikipedia.org/wiki/Logical_conjunction'>AND</a>ed
|
||||
together with this set.</p>
|
||||
<p>If you want to list the set contents only, please note the default
|
||||
value of the <b>status</b> parameter! You may want to override it
|
||||
in order to include unavailable and/or archived geocaches within the set.</p>
|
||||
</opt>
|
||||
<opt name='limit' default='100'>
|
||||
<p>Integer in range 1..500. Maximum number of cache codes returned.</p>
|
||||
</opt>
|
||||
<opt name='offset' default='0'>
|
||||
<p>An offset, the amount of items to skip at the beginning of the result. Combined with limit
|
||||
allows pagination of the result set. Please note, that the sum of offset and limit still cannot
|
||||
exceed 500. You MAY NOT use this method to list all the caches, it is for searching only.
|
||||
Have a peek at the <b>replicate</b> module if you need all the caches.</p>
|
||||
</opt>
|
||||
<opt name='order_by'>
|
||||
<p>Pipe separated list of fields to order the results by. Prefix the field name with
|
||||
a '-' sign to indicate a descending order.</p>
|
||||
<p>Currently, fields which you can order by include: <b>code</b>, <b>name</b>,
|
||||
<b>founds</b>, <b>rcmds</b>, <b>rcmds%</b> (tell us if you want more).</p>
|
||||
<p><b>Examples:</b></p>
|
||||
<ul>
|
||||
<li>to order by cache name use "order_by=name" or "order_by=+name",</li>
|
||||
<li>to have the most recommended caches in front, use "order_by=-rcmds%",</li>
|
||||
<li>multicolumn sorting is also allowed, ex. "order_by=-founds|name"</li>
|
||||
</ul>
|
||||
<p><b>Note:</b> Try to avoid executing separate OKAPI request every time you
|
||||
want to sort the data which you <b>already have</b>. Consider caching and
|
||||
sorting on client side. This will speed up things for both sides.</p>
|
||||
<p><b>Note:</b> For most other methods (like <b>bbox</b> and <b>nearest</b>),
|
||||
the default order is <i>by the distance from the center</i>. If you supply
|
||||
custom <b>order_by</b> parameter, then we will try to order by your preference
|
||||
first, and then by the distance later.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>results</b> - a list of cache codes,</li>
|
||||
<li><b>more</b> - boolean, <b>true</b> means that there were more
|
||||
results for your query, but they were not returned because of the
|
||||
<b>limit</b> parameter.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -12,76 +12,83 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# You may wonder, why there are no parameters like "bbox" or "center" in the
|
||||
# "search/all" method. This is *intentional* and should be kept this way.
|
||||
# Such parameters would fall in conflict with each other and - in result -
|
||||
# make the documentation very fuzzy. That's why they were intentionally
|
||||
# left out of the "search/all" method, and put in separate (individual) ones.
|
||||
# It's much easier to grasp their meaning this way.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# You may wonder, why there are no parameters like "bbox" or "center" in the
|
||||
# "search/all" method. This is *intentional* and should be kept this way.
|
||||
# Such parameters would fall in conflict with each other and - in result -
|
||||
# make the documentation very fuzzy. That's why they were intentionally
|
||||
# left out of the "search/all" method, and put in separate (individual) ones.
|
||||
# It's much easier to grasp their meaning this way.
|
||||
|
||||
$tmp = $request->get_parameter('bbox');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('bbox');
|
||||
$parts = explode('|', $tmp);
|
||||
if (count($parts) != 4)
|
||||
throw new InvalidParam('bbox', "Expecting 4 pipe-separated parts, got ".count($parts).".");
|
||||
foreach ($parts as &$part_ref)
|
||||
{
|
||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $part_ref))
|
||||
throw new InvalidParam('bbox', "'$part_ref' is not a valid float number.");
|
||||
$part_ref = floatval($part_ref);
|
||||
}
|
||||
list($bbsouth, $bbwest, $bbnorth, $bbeast) = $parts;
|
||||
if ($bbnorth <= $bbsouth)
|
||||
throw new InvalidParam('bbox', "Northern edge must be situated to the north of the southern edge.");
|
||||
if ($bbeast == $bbwest)
|
||||
throw new InvalidParam('bbox', "Eastern edge longitude is the same as the western one.");
|
||||
if ($bbnorth > 90 || $bbnorth < -90 || $bbsouth > 90 || $bbsouth < -90)
|
||||
throw new InvalidParam('bbox', "Latitudes have to be within -90..90 range.");
|
||||
if ($bbeast > 180 || $bbeast < -180 || $bbwest > 180 || $bbwest < -180)
|
||||
throw new InvalidParam('bbox', "Longitudes have to be within -180..180 range.");
|
||||
$tmp = $request->get_parameter('bbox');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('bbox');
|
||||
$parts = explode('|', $tmp);
|
||||
if (count($parts) != 4)
|
||||
throw new InvalidParam('bbox', "Expecting 4 pipe-separated parts, got ".count($parts).".");
|
||||
foreach ($parts as &$part_ref)
|
||||
{
|
||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $part_ref))
|
||||
throw new InvalidParam('bbox', "'$part_ref' is not a valid float number.");
|
||||
$part_ref = floatval($part_ref);
|
||||
}
|
||||
list($bbsouth, $bbwest, $bbnorth, $bbeast) = $parts;
|
||||
if ($bbnorth <= $bbsouth)
|
||||
throw new InvalidParam('bbox', "Northern edge must be situated to the north of the southern edge.");
|
||||
if ($bbeast == $bbwest)
|
||||
throw new InvalidParam('bbox', "Eastern edge longitude is the same as the western one.");
|
||||
if ($bbnorth > 90 || $bbnorth < -90 || $bbsouth > 90 || $bbsouth < -90)
|
||||
throw new InvalidParam('bbox', "Latitudes have to be within -90..90 range.");
|
||||
if ($bbeast > 180 || $bbeast < -180 || $bbwest > 180 || $bbwest < -180)
|
||||
throw new InvalidParam('bbox', "Longitudes have to be within -180..180 range.");
|
||||
|
||||
# Construct SQL conditions for the specified bounding box.
|
||||
# Construct SQL conditions for the specified bounding box.
|
||||
|
||||
$where_conds = array();
|
||||
$where_conds[] = "caches.latitude between '".mysql_real_escape_string($bbsouth)."' and '".mysql_real_escape_string($bbnorth)."'";
|
||||
if ($bbeast > $bbwest)
|
||||
{
|
||||
# Easy one.
|
||||
$where_conds[] = "caches.longitude between '".mysql_real_escape_string($bbwest)."' and '".mysql_real_escape_string($bbeast)."'";
|
||||
}
|
||||
else
|
||||
{
|
||||
# We'll have to assume that this box goes through the 180-degree meridian.
|
||||
# For example, $bbwest = 179 and $bbeast = -179.
|
||||
$where_conds[] = "(caches.longitude > '".mysql_real_escape_string($bbwest)."' or caches.longitude < '".mysql_real_escape_string($bbeast)."')";
|
||||
}
|
||||
$search_assistant = new SearchAssistant($request);
|
||||
$search_assistant->prepare_common_search_params();
|
||||
$search_assistant->prepare_location_search_params();
|
||||
|
||||
#
|
||||
# In the method description, we promised to return caches ordered by the *rough*
|
||||
# distance from the center of the bounding box. We'll use ORDER BY with a simplified
|
||||
# distance formula and combine it with the LIMIT clause to get the best results.
|
||||
#
|
||||
$where_conds = array();
|
||||
$where_conds[] = $search_assistant->get_latitude_expr()." between '".mysql_real_escape_string($bbsouth)."' and '".mysql_real_escape_string($bbnorth)."'";
|
||||
if ($bbeast > $bbwest)
|
||||
{
|
||||
# Easy one.
|
||||
$where_conds[] = $search_assistant->get_longitude_expr()." between '".mysql_real_escape_string($bbwest)."' and '".mysql_real_escape_string($bbeast)."'";
|
||||
}
|
||||
else
|
||||
{
|
||||
# We'll have to assume that this box goes through the 180-degree meridian.
|
||||
# For example, $bbwest = 179 and $bbeast = -179.
|
||||
$where_conds[] = "(".$search_assistant->get_longitude_expr()." > '".mysql_real_escape_string($bbwest)
|
||||
."' or ".$search_assistant->get_longitude_expr()." < '".mysql_real_escape_string($bbeast)."')";
|
||||
}
|
||||
|
||||
$center_lat = ($bbsouth + $bbnorth) / 2.0;
|
||||
$center_lon = ($bbwest + $bbeast) / 2.0;
|
||||
#
|
||||
# In the method description, we promised to return caches ordered by the *rough*
|
||||
# distance from the center of the bounding box. We'll use ORDER BY with a simplified
|
||||
# distance formula and combine it with the LIMIT clause to get the best results.
|
||||
#
|
||||
|
||||
$search_params = SearchAssistant::get_common_search_params($request);
|
||||
$search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
|
||||
$search_params['order_by'][] = Okapi::get_distance_sql($center_lat, $center_lon,
|
||||
"caches.latitude", "caches.longitude"); # not replaced; added to the end!
|
||||
$center_lat = ($bbsouth + $bbnorth) / 2.0;
|
||||
$center_lon = ($bbwest + $bbeast) / 2.0;
|
||||
|
||||
$result = SearchAssistant::get_common_search_result($search_params);
|
||||
$search_params = $search_assistant->get_search_params();
|
||||
$search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
|
||||
$search_params['order_by'][] = Okapi::get_distance_sql($center_lat, $center_lon,
|
||||
$search_assistant->get_latitude_expr(),
|
||||
$search_assistant->get_longitude_expr()); # not replaced; added to the end!
|
||||
$search_assistant->set_search_params($search_params);
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$result = $search_assistant->get_common_search_result();
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,38 @@
|
||||
<xml>
|
||||
<brief>Search for caches within specified bounding box</brief>
|
||||
<issue-id>16</issue-id>
|
||||
<desc>
|
||||
<p>This method is similar to the search/all method, but the results
|
||||
are restricted to the caches situated within a given bounding box
|
||||
(a rectangle on the map).</p>
|
||||
<p>Unless overriden, results are ordered by the distance from the center of the bounding
|
||||
box. This means, that if you hit the limit of geocaches
|
||||
returned, you will receive the ones that are in the middle of your
|
||||
box, and miss the ones on the edges.</p>
|
||||
<p>Usually you will want to use search_and_retrieve method instead of this one.
|
||||
This way, you can get much more data in <b>one request</b>.</p>
|
||||
</desc>
|
||||
<req name='bbox'>
|
||||
<p>The bounding box within to search for caches. The box is defined
|
||||
by a string in "<b>S|W|N|E</b>" format, where:</p>
|
||||
<ul>
|
||||
<li><b>S</b> stands for southern edge latitude of the box,</li>
|
||||
<li><b>W</b> stands for western edge longitude of the box,</li>
|
||||
<li><b>N</b> stands for northern edge latitude of the box,</li>
|
||||
<li><b>E</b> stands for eastern edge longitude of the box.</li>
|
||||
</ul>
|
||||
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||
longitudes in the eastern hemisphere (and negative for southern and
|
||||
western hemispheres accordingly). These are full degrees with a dot
|
||||
as a decimal point (ex. "48.7|15.8|54|24.9").</p>
|
||||
</req>
|
||||
<import-params method='services/caches/search/all'/>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>Same format as in the search/all method.</p>
|
||||
</returns>
|
||||
<brief>Search for caches within specified bounding box</brief>
|
||||
<issue-id>16</issue-id>
|
||||
<desc>
|
||||
<p>This method is similar to the search/all method, but the results
|
||||
are restricted to the caches situated within a given bounding box
|
||||
(a rectangle on the map).</p>
|
||||
<p>Unless overriden, results are ordered by the distance from the center of the bounding
|
||||
box. This means, that if you hit the limit of geocaches
|
||||
returned, you will receive the ones that are in the middle of your
|
||||
box, and miss the ones on the edges.</p>
|
||||
<p>Usually you will want to use search_and_retrieve method instead of this one.
|
||||
This way, you can get much more data in <b>one request</b>.</p>
|
||||
</desc>
|
||||
<req name='bbox'>
|
||||
<p>The bounding box within to search for caches. The box is defined
|
||||
by a string in "<b>S|W|N|E</b>" format, where:</p>
|
||||
<ul>
|
||||
<li><b>S</b> stands for southern edge latitude of the box,</li>
|
||||
<li><b>W</b> stands for western edge longitude of the box,</li>
|
||||
<li><b>N</b> stands for northern edge latitude of the box,</li>
|
||||
<li><b>E</b> stands for eastern edge longitude of the box.</li>
|
||||
</ul>
|
||||
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||
longitudes in the eastern hemisphere (and negative for southern and
|
||||
western hemispheres accordingly). These are full degrees with a dot
|
||||
as a decimal point (ex. "48.7|15.8|54|24.9").</p>
|
||||
</req>
|
||||
<opt name='location_source' default='default-coords'>
|
||||
Same as in the <a href="%OKAPI:methodargref:services/caches/search/nearest#location_source%">
|
||||
services/caches/search/nearest</a> method.
|
||||
</opt>
|
||||
<import-params method='services/caches/search/all'/>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>Same format as in the search/all method.</p>
|
||||
</returns>
|
||||
</xml>
|
||||
|
@ -13,165 +13,165 @@ use okapi\Db;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of: array('cache_code', 'OPXXXX'), array('internal_id', '12345'),
|
||||
* array('uuid', 'A408C3...') or null.
|
||||
*/
|
||||
private static function get_cache_key($url)
|
||||
{
|
||||
# Determine our own domain.
|
||||
/**
|
||||
* Returns one of: array('cache_code', 'OPXXXX'), array('internal_id', '12345'),
|
||||
* array('uuid', 'A408C3...') or null.
|
||||
*/
|
||||
private static function get_cache_key($url)
|
||||
{
|
||||
# Determine our own domain.
|
||||
|
||||
static $host = null;
|
||||
static $length = null;
|
||||
if ($host == null)
|
||||
{
|
||||
$host = parse_url(Settings::get('SITE_URL'), PHP_URL_HOST);
|
||||
if (strpos($host, "www.") === 0)
|
||||
$host = substr($host, 4);
|
||||
$length = strlen($host);
|
||||
}
|
||||
static $host = null;
|
||||
static $length = null;
|
||||
if ($host == null)
|
||||
{
|
||||
$host = parse_url(Settings::get('SITE_URL'), PHP_URL_HOST);
|
||||
if (strpos($host, "www.") === 0)
|
||||
$host = substr($host, 4);
|
||||
$length = strlen($host);
|
||||
}
|
||||
|
||||
# Parse the URL
|
||||
# Parse the URL
|
||||
|
||||
$uri = parse_url($url);
|
||||
if ($uri == false)
|
||||
return null;
|
||||
if ((!isset($uri['scheme'])) || (!in_array($uri['scheme'], array('http', 'https'))))
|
||||
return null;
|
||||
if ((!isset($uri['host'])) || (substr($uri['host'], -$length) != $host))
|
||||
return null;
|
||||
if (!isset($uri['path']))
|
||||
return null;
|
||||
if (preg_match("#^/(O[A-Z][A-Z0-9]{4,5})$#", $uri['path'], $matches))
|
||||
{
|
||||
# Some servers allow "http://oc.xx/<cache_code>" shortcut.
|
||||
return array('cache_code', $matches[1]);
|
||||
}
|
||||
$parts = array();
|
||||
if (isset($uri['query']))
|
||||
$parts = array_merge($parts, explode('&', $uri['query']));
|
||||
if (isset($uri['fragment']))
|
||||
$parts = array_merge($parts, explode('&', $uri['fragment']));
|
||||
foreach ($parts as $param)
|
||||
{
|
||||
$item = explode('=', $param, 2);
|
||||
if (count($item) != 2)
|
||||
continue;
|
||||
$key = $item[0];
|
||||
$value = $item[1];
|
||||
if ($key == 'wp')
|
||||
return array('cache_code', $value);
|
||||
if ($key == 'cacheid')
|
||||
return array('internal_id', $value);
|
||||
if ($key == 'uuid')
|
||||
return array('uuid', $value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
$uri = parse_url($url);
|
||||
if ($uri == false)
|
||||
return null;
|
||||
if ((!isset($uri['scheme'])) || (!in_array($uri['scheme'], array('http', 'https'))))
|
||||
return null;
|
||||
if ((!isset($uri['host'])) || (substr($uri['host'], -$length) != $host))
|
||||
return null;
|
||||
if (!isset($uri['path']))
|
||||
return null;
|
||||
if (preg_match("#^/(O[A-Z][A-Z0-9]{4,5})$#", $uri['path'], $matches))
|
||||
{
|
||||
# Some servers allow "http://oc.xx/<cache_code>" shortcut.
|
||||
return array('cache_code', $matches[1]);
|
||||
}
|
||||
$parts = array();
|
||||
if (isset($uri['query']))
|
||||
$parts = array_merge($parts, explode('&', $uri['query']));
|
||||
if (isset($uri['fragment']))
|
||||
$parts = array_merge($parts, explode('&', $uri['fragment']));
|
||||
foreach ($parts as $param)
|
||||
{
|
||||
$item = explode('=', $param, 2);
|
||||
if (count($item) != 2)
|
||||
continue;
|
||||
$key = $item[0];
|
||||
$value = $item[1];
|
||||
if ($key == 'wp')
|
||||
return array('cache_code', $value);
|
||||
if ($key == 'cacheid')
|
||||
return array('internal_id', $value);
|
||||
if ($key == 'uuid')
|
||||
return array('uuid', $value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Retrieve the list of URLs to check.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Retrieve the list of URLs to check.
|
||||
|
||||
$tmp = $request->get_parameter('urls');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('urls');
|
||||
$urls = explode('|', $tmp);
|
||||
$as_dict = $request->get_parameter('as_dict');
|
||||
if (!$as_dict) $as_dict = 'false';
|
||||
if (!in_array($as_dict, array('true', 'false')))
|
||||
throw new InvalidParam('as_dict');
|
||||
$as_dict = ($as_dict == 'true');
|
||||
$tmp = $request->get_parameter('urls');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('urls');
|
||||
$urls = explode('|', $tmp);
|
||||
$as_dict = $request->get_parameter('as_dict');
|
||||
if (!$as_dict) $as_dict = 'false';
|
||||
if (!in_array($as_dict, array('true', 'false')))
|
||||
throw new InvalidParam('as_dict');
|
||||
$as_dict = ($as_dict == 'true');
|
||||
|
||||
# Generate the lists of keys.
|
||||
# Generate the lists of keys.
|
||||
|
||||
$results = array();
|
||||
$urls_with = array(
|
||||
'cache_code' => array(),
|
||||
'internal_id' => array(),
|
||||
'uuid' => array()
|
||||
);
|
||||
foreach ($urls as &$url_ref)
|
||||
{
|
||||
$key = self::get_cache_key($url_ref);
|
||||
if ($key != null)
|
||||
$urls_with[$key[0]][$url_ref] = $key[1];
|
||||
else
|
||||
$results[$url_ref] = null;
|
||||
}
|
||||
$results = array();
|
||||
$urls_with = array(
|
||||
'cache_code' => array(),
|
||||
'internal_id' => array(),
|
||||
'uuid' => array()
|
||||
);
|
||||
foreach ($urls as &$url_ref)
|
||||
{
|
||||
$key = self::get_cache_key($url_ref);
|
||||
if ($key != null)
|
||||
$urls_with[$key[0]][$url_ref] = $key[1];
|
||||
else
|
||||
$results[$url_ref] = null;
|
||||
}
|
||||
|
||||
# Include 'cache_code' references.
|
||||
# Include 'cache_code' references.
|
||||
|
||||
foreach ($urls_with['cache_code'] as $url => $cache_code)
|
||||
$results[$url] = $cache_code;
|
||||
foreach ($urls_with['cache_code'] as $url => $cache_code)
|
||||
$results[$url] = $cache_code;
|
||||
|
||||
# Include 'internal_id' references.
|
||||
# Include 'internal_id' references.
|
||||
|
||||
$internal_ids = array_values($urls_with['internal_id']);
|
||||
if (count($internal_ids) > 0)
|
||||
{
|
||||
$rs = Db::query("
|
||||
select cache_id, wp_oc
|
||||
from caches
|
||||
where
|
||||
cache_id in ('".implode("','", array_map('mysql_real_escape_string', $internal_ids))."')
|
||||
and status in (1,2,3)
|
||||
");
|
||||
$dict = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$dict[$row['cache_id']] = $row['wp_oc'];
|
||||
foreach ($urls_with['internal_id'] as $url => $internal_id)
|
||||
{
|
||||
if (isset($dict[$internal_id]))
|
||||
$results[$url] = $dict[$internal_id];
|
||||
else
|
||||
$results[$url] = null;
|
||||
}
|
||||
}
|
||||
$internal_ids = array_values($urls_with['internal_id']);
|
||||
if (count($internal_ids) > 0)
|
||||
{
|
||||
$rs = Db::query("
|
||||
select cache_id, wp_oc
|
||||
from caches
|
||||
where
|
||||
cache_id in ('".implode("','", array_map('mysql_real_escape_string', $internal_ids))."')
|
||||
and status in (1,2,3)
|
||||
");
|
||||
$dict = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$dict[$row['cache_id']] = $row['wp_oc'];
|
||||
foreach ($urls_with['internal_id'] as $url => $internal_id)
|
||||
{
|
||||
if (isset($dict[$internal_id]))
|
||||
$results[$url] = $dict[$internal_id];
|
||||
else
|
||||
$results[$url] = null;
|
||||
}
|
||||
}
|
||||
|
||||
# Include 'uuid' references.
|
||||
# Include 'uuid' references.
|
||||
|
||||
$uuids = array_values($urls_with['uuid']);
|
||||
if (count($uuids) > 0)
|
||||
{
|
||||
$rs = Db::query("
|
||||
select uuid, wp_oc
|
||||
from caches
|
||||
where
|
||||
uuid in ('".implode("','", array_map('mysql_real_escape_string', $uuids))."')
|
||||
and status in (1,2,3)
|
||||
");
|
||||
$dict = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$dict[$row['uuid']] = $row['wp_oc'];
|
||||
foreach ($urls_with['uuid'] as $url => $uuid)
|
||||
{
|
||||
if (isset($dict[$uuid]))
|
||||
$results[$url] = $dict[$uuid];
|
||||
else
|
||||
$results[$url] = null;
|
||||
}
|
||||
}
|
||||
$uuids = array_values($urls_with['uuid']);
|
||||
if (count($uuids) > 0)
|
||||
{
|
||||
$rs = Db::query("
|
||||
select uuid, wp_oc
|
||||
from caches
|
||||
where
|
||||
uuid in ('".implode("','", array_map('mysql_real_escape_string', $uuids))."')
|
||||
and status in (1,2,3)
|
||||
");
|
||||
$dict = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$dict[$row['uuid']] = $row['wp_oc'];
|
||||
foreach ($urls_with['uuid'] as $url => $uuid)
|
||||
{
|
||||
if (isset($dict[$uuid]))
|
||||
$results[$url] = $dict[$uuid];
|
||||
else
|
||||
$results[$url] = null;
|
||||
}
|
||||
}
|
||||
|
||||
# Format the results according to the 'as_dict' parameter.
|
||||
# Format the results according to the 'as_dict' parameter.
|
||||
|
||||
if ($as_dict)
|
||||
return Okapi::formatted_response($request, $results);
|
||||
else
|
||||
{
|
||||
$cache_codes = array();
|
||||
foreach ($results as $url => $cache_code)
|
||||
if ($cache_code != null)
|
||||
$cache_codes[$cache_code] = true;
|
||||
$flattened = array('results' => array_keys($cache_codes));
|
||||
return Okapi::formatted_response($request, $flattened);
|
||||
}
|
||||
}
|
||||
if ($as_dict)
|
||||
return Okapi::formatted_response($request, $results);
|
||||
else
|
||||
{
|
||||
$cache_codes = array();
|
||||
foreach ($results as $url => $cache_code)
|
||||
if ($cache_code != null)
|
||||
$cache_codes[$cache_code] = true;
|
||||
$flattened = array('results' => array_keys($cache_codes));
|
||||
return Okapi::formatted_response($request, $flattened);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,32 @@
|
||||
<xml>
|
||||
<brief>Resolve cache references from given URLs</brief>
|
||||
<issue-id>116</issue-id>
|
||||
<desc>
|
||||
<p>Given a set of URLs, determine codes of geocaches referenced within them.</p>
|
||||
<p>This might be useful if you have a link to an Opencaching geocache page, but you're
|
||||
not able to extract cache code from such link (and you need the cache code to operate
|
||||
on a cache using OKAPI). Geocache pages may be referenced using various types of URLs,
|
||||
only some of them contain the cache code.</p>
|
||||
</desc>
|
||||
<req name='urls'>
|
||||
<p>Pipe-separated list of URLs. No more than 500.</p>
|
||||
</req>
|
||||
<opt name='as_dict' default='false'>
|
||||
<p>If <b>false</b>, then the result of this method will be compatible with
|
||||
search/all method (and therefore can be used with search_and_retrieve).</p>
|
||||
<p>If <b>true</b>, then the result will be a dictionary. Your URLs will be
|
||||
mapped to the keys of this dictionary. Each value will be either a string
|
||||
(cache code) or null (if no cache code was found for the given URL).</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>As described in the <b>as_dict</b> parameter.</p>
|
||||
<p>Examples:</p>
|
||||
<p>For <i>by_urls?urls=url1|url2|url3</i>
|
||||
query, the result might look something link this:</p>
|
||||
<pre>{"results": ["OP28F9"]}</pre>
|
||||
<p>For <i>by_urls?urls=url1|url2|url3&as_dict=true</i>
|
||||
query, the result might look something link this:</p>
|
||||
<pre>{"url1": "OP28F9", "url2": null, "url3": "OP28F9"}</pre>
|
||||
</returns>
|
||||
<brief>Resolve cache references from given URLs</brief>
|
||||
<issue-id>116</issue-id>
|
||||
<desc>
|
||||
<p>Given a set of URLs, determine codes of geocaches referenced within them.</p>
|
||||
<p>This might be useful if you have a link to an Opencaching geocache page, but you're
|
||||
not able to extract cache code from such link (and you need the cache code to operate
|
||||
on a cache using OKAPI). Geocache pages may be referenced using various types of URLs,
|
||||
only some of them contain the cache code.</p>
|
||||
</desc>
|
||||
<req name='urls'>
|
||||
<p>Pipe-separated list of URLs. No more than 500.</p>
|
||||
</req>
|
||||
<opt name='as_dict' default='false'>
|
||||
<p>If <b>false</b>, then the result of this method will be compatible with
|
||||
search/all method (and therefore can be used with search_and_retrieve).</p>
|
||||
<p>If <b>true</b>, then the result will be a dictionary. Your URLs will be
|
||||
mapped to the keys of this dictionary. Each value will be either a string
|
||||
(cache code) or null (if no cache code was found for the given URL).</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>As described in the <b>as_dict</b> parameter.</p>
|
||||
<p>Examples:</p>
|
||||
<p>For <i>by_urls?urls=url1|url2|url3</i>
|
||||
query, the result might look something link this:</p>
|
||||
<pre>{"results": ["OP28F9"]}</pre>
|
||||
<p>For <i>by_urls?urls=url1|url2|url3&as_dict=true</i>
|
||||
query, the result might look something link this:</p>
|
||||
<pre>{"url1": "OP28F9", "url2": null, "url3": "OP28F9"}</pre>
|
||||
</returns>
|
||||
</xml>
|
||||
|
@ -12,75 +12,82 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# You may wonder, why there are no parameters like "bbox" or "center" in the
|
||||
# "search/all" method. This is *intentional* and should be kept this way.
|
||||
# Such parameters would fall in conflict with each other and - in result -
|
||||
# make the documentation very fuzzy. That's why they were intentionally
|
||||
# left out of the "search/all" method, and put in separate (individual) ones.
|
||||
# It's much easier to grasp their meaning this way.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# You may wonder, why there are no parameters like "bbox" or "center" in the
|
||||
# "search/all" method. This is *intentional* and should be kept this way.
|
||||
# Such parameters would fall in conflict with each other and - in result -
|
||||
# make the documentation very fuzzy. That's why they were intentionally
|
||||
# left out of the "search/all" method, and put in separate (individual) ones.
|
||||
# It's much easier to grasp their meaning this way.
|
||||
|
||||
$tmp = $request->get_parameter('center');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('center');
|
||||
$parts = explode('|', $tmp);
|
||||
if (count($parts) != 2)
|
||||
throw new InvalidParam('center', "Expecting 2 pipe-separated parts, got ".count($parts).".");
|
||||
foreach ($parts as &$part_ref)
|
||||
{
|
||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $part_ref))
|
||||
throw new InvalidParam('center', "'$part_ref' is not a valid float number.");
|
||||
$part_ref = floatval($part_ref);
|
||||
}
|
||||
list($center_lat, $center_lon) = $parts;
|
||||
if ($center_lat > 90 || $center_lat < -90)
|
||||
throw new InvalidParam('center', "Latitudes have to be within -90..90 range.");
|
||||
if ($center_lon > 180 || $center_lon < -180)
|
||||
throw new InvalidParam('center', "Longitudes have to be within -180..180 range.");
|
||||
$tmp = $request->get_parameter('center');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('center');
|
||||
$parts = explode('|', $tmp);
|
||||
if (count($parts) != 2)
|
||||
throw new InvalidParam('center', "Expecting 2 pipe-separated parts, got ".count($parts).".");
|
||||
foreach ($parts as &$part_ref)
|
||||
{
|
||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $part_ref))
|
||||
throw new InvalidParam('center', "'$part_ref' is not a valid float number.");
|
||||
$part_ref = floatval($part_ref);
|
||||
}
|
||||
list($center_lat, $center_lon) = $parts;
|
||||
if ($center_lat > 90 || $center_lat < -90)
|
||||
throw new InvalidParam('center', "Latitudes have to be within -90..90 range.");
|
||||
if ($center_lon > 180 || $center_lon < -180)
|
||||
throw new InvalidParam('center', "Longitudes have to be within -180..180 range.");
|
||||
|
||||
#
|
||||
# In the method description, we promised to return caches ordered by the *rough*
|
||||
# distance from the center point. We'll use ORDER BY with a simplified distance
|
||||
# formula and combine it with the LIMIT clause to get the best results.
|
||||
#
|
||||
#
|
||||
# In the method description, we promised to return caches ordered by the *rough*
|
||||
# distance from the center point. We'll use ORDER BY with a simplified distance
|
||||
# formula and combine it with the LIMIT clause to get the best results.
|
||||
#
|
||||
|
||||
$distance_formula = Okapi::get_distance_sql($center_lat, $center_lon, "caches.latitude", "caches.longitude");
|
||||
$search_assistant = new SearchAssistant($request);
|
||||
$search_assistant->prepare_common_search_params();
|
||||
$search_assistant->prepare_location_search_params();
|
||||
$distance_formula = Okapi::get_distance_sql(
|
||||
$center_lat, $center_lon,
|
||||
$search_assistant->get_latitude_expr(), $search_assistant->get_longitude_expr()
|
||||
);
|
||||
|
||||
# 'radius' parameter is optional. If not given, we'll have to calculate the
|
||||
# distance for every cache in the database.
|
||||
# 'radius' parameter is optional. If not given, we'll have to calculate the
|
||||
# distance for every cache in the database.
|
||||
|
||||
$where_conds = array();
|
||||
$radius = null;
|
||||
if ($tmp = $request->get_parameter('radius'))
|
||||
{
|
||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $tmp))
|
||||
throw new InvalidParam('radius', "'$tmp' is not a valid float number.");
|
||||
$radius = floatval($tmp);
|
||||
if ($radius <= 0)
|
||||
throw new InvalidParam('radius', "Has to be a positive number.");
|
||||
$radius *= 1000; # this one is given in kilemeters, converting to meters!
|
||||
$where_conds[] = "$distance_formula <= '".mysql_real_escape_string($radius)."'";
|
||||
}
|
||||
$where_conds = array();
|
||||
$radius = null;
|
||||
if ($tmp = $request->get_parameter('radius'))
|
||||
{
|
||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $tmp))
|
||||
throw new InvalidParam('radius', "'$tmp' is not a valid float number.");
|
||||
$radius = floatval($tmp);
|
||||
if ($radius <= 0)
|
||||
throw new InvalidParam('radius', "Has to be a positive number.");
|
||||
$radius *= 1000; # this one is given in kilemeters, converting to meters!
|
||||
$where_conds[] = "$distance_formula <= '".mysql_real_escape_string($radius)."'";
|
||||
}
|
||||
|
||||
$search_params = SearchAssistant::get_common_search_params($request);
|
||||
$search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
|
||||
$search_params['order_by'][] = $distance_formula; # not replaced; added to the end!
|
||||
$search_params = $search_assistant->get_search_params();
|
||||
$search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
|
||||
$search_params['order_by'][] = $distance_formula; # not replaced; added to the end!
|
||||
$search_assistant->set_search_params($search_params);
|
||||
|
||||
$result = SearchAssistant::get_common_search_result($search_params);
|
||||
if ($radius == null)
|
||||
{
|
||||
# 'more' is meaningless in this case, we'll remove it.
|
||||
unset($result['more']);
|
||||
}
|
||||
$result = $search_assistant->get_common_search_result();
|
||||
if ($radius == null)
|
||||
{
|
||||
# 'more' is meaningless in this case, we'll remove it.
|
||||
unset($result['more']);
|
||||
}
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,44 @@
|
||||
<xml>
|
||||
<brief>Search for nearest geocaches</brief>
|
||||
<issue-id>17</issue-id>
|
||||
<desc>
|
||||
<p>Find the nearest geocaches. Unless overriden, results are ordered by the distance from
|
||||
the given center point.</p>
|
||||
<p>Usually you will want to use search_and_retrieve method instead of this one.
|
||||
This way, you can get much more data in <b>one request</b>.</p>
|
||||
</desc>
|
||||
<req name='center'>
|
||||
<p>The center point (typically - the user's location), in the
|
||||
"lat|lon" format.</p>
|
||||
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||
longitudes in the eastern hemisphere (and negative for southern and
|
||||
western hemispheres accordingly). These are full degrees with a dot
|
||||
as a decimal point (ex. "54.3|22.3").</p>
|
||||
</req>
|
||||
<opt name='radius'>
|
||||
<p>Maximal distance (from the center point) for the cache to
|
||||
be included in the results. Unlike in most other places, this
|
||||
distance is given <b>in kilometers</b> instead of meters
|
||||
(it can contain a floating point though).</p>
|
||||
</opt>
|
||||
<import-params method='services/caches/search/all'/>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>Same format as in the search/all method. The <b>more</b> key will
|
||||
be skipped when no <b>radius</b> argument is given.</p>
|
||||
</returns>
|
||||
<brief>Search for nearest geocaches</brief>
|
||||
<issue-id>17</issue-id>
|
||||
<desc>
|
||||
<p>Find the nearest geocaches. Unless overriden, results are ordered by the distance from
|
||||
the given center point.</p>
|
||||
<p>Usually you will want to use search_and_retrieve method instead of this one.
|
||||
This way, you can get much more data in <b>one request</b>.</p>
|
||||
</desc>
|
||||
<req name='center'>
|
||||
<p>The center point (typically - the user's location), in the
|
||||
"lat|lon" format.</p>
|
||||
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||
longitudes in the eastern hemisphere (and negative for southern and
|
||||
western hemispheres accordingly). These are full degrees with a dot
|
||||
as a decimal point (ex. "54.3|22.3").</p>
|
||||
</req>
|
||||
<opt name='radius'>
|
||||
<p>Maximal distance (from the center point) for the cache to
|
||||
be included in the results. Unlike in most other places, this
|
||||
distance is given <b>in kilometers</b> instead of meters
|
||||
(it can contain a floating point though).</p>
|
||||
</opt>
|
||||
<opt name='location_source' default='default-coords'>
|
||||
<p>In general, this parameter should take the same value as in the
|
||||
<a href="%OKAPI:methodargref:services/caches/formatters/gpx#location_source%">
|
||||
services/caches/formatters/gpx</a> method, but currently <u>only two values are
|
||||
supported</u>: <b>default-coords</b> and <b>alt_wpt:user-coords</b>.</p>
|
||||
|
||||
<p>Allows you to search among alternate locations of the geocache,
|
||||
instead of the default one. Particularily useful with <b>alt_wpt:user-coords</b>
|
||||
alternate waypoint.</p>
|
||||
|
||||
<p>Please note, that if you plan on using this option in conjunction
|
||||
with <b>search_and_retrieve</b> method, then you'd probably want to use
|
||||
the same option in your <i>retr_method</i> too (if available).</p>
|
||||
</opt>
|
||||
<import-params method='services/caches/search/all'/>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>Same format as in the search/all method. The <b>more</b> key will
|
||||
be skipped when no <b>radius</b> argument is given.</p>
|
||||
</returns>
|
||||
</xml>
|
||||
|
@ -14,169 +14,171 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get [set_id, date_created, expires] for the given params_hash
|
||||
* (or [null, null, null] if not found).
|
||||
*/
|
||||
private static function find_param_set($params_hash, $ref_max_age)
|
||||
{
|
||||
$tmp = Db::select_row("
|
||||
select
|
||||
id as id,
|
||||
unix_timestamp(date_created) as date_created,
|
||||
unix_timestamp(expires) as expires
|
||||
from okapi_search_sets
|
||||
where
|
||||
params_hash = '".mysql_real_escape_string($params_hash)."'
|
||||
and date_add(date_created, interval '".mysql_real_escape_string($ref_max_age)."' second) > now()
|
||||
order by id desc
|
||||
limit 1
|
||||
");
|
||||
if ($tmp === null)
|
||||
return array(null, null, null);
|
||||
return array($tmp['id'], $tmp['date_created'], $tmp['expires']);
|
||||
}
|
||||
/**
|
||||
* Get [set_id, date_created, expires] for the given params_hash
|
||||
* (or [null, null, null] if not found).
|
||||
*/
|
||||
private static function find_param_set($params_hash, $ref_max_age)
|
||||
{
|
||||
$tmp = Db::select_row("
|
||||
select
|
||||
id as id,
|
||||
unix_timestamp(date_created) as date_created,
|
||||
unix_timestamp(expires) as expires
|
||||
from okapi_search_sets
|
||||
where
|
||||
params_hash = '".mysql_real_escape_string($params_hash)."'
|
||||
and date_add(date_created, interval '".mysql_real_escape_string($ref_max_age)."' second) > now()
|
||||
order by id desc
|
||||
limit 1
|
||||
");
|
||||
if ($tmp === null)
|
||||
return array(null, null, null);
|
||||
return array($tmp['id'], $tmp['date_created'], $tmp['expires']);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# "Cache control" parameters.
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# "Cache control" parameters.
|
||||
|
||||
$tmp = $request->get_parameter('min_store');
|
||||
if ($tmp === null) $tmp = "300";
|
||||
$min_store = intval($tmp);
|
||||
if (("$min_store" !== $tmp) ||($min_store < 0) || ($min_store > 64800))
|
||||
throw new InvalidParam('min_store', "Has to be in the 0..64800 range.");
|
||||
$tmp = $request->get_parameter('min_store');
|
||||
if ($tmp === null) $tmp = "300";
|
||||
$min_store = intval($tmp);
|
||||
if (("$min_store" !== $tmp) ||($min_store < 0) || ($min_store > 64800))
|
||||
throw new InvalidParam('min_store', "Has to be in the 0..64800 range.");
|
||||
|
||||
$tmp = $request->get_parameter('ref_max_age');
|
||||
if ($tmp === null) $tmp = "300";
|
||||
if ($tmp == "nolimit") $tmp = "9999999";
|
||||
$ref_max_age = intval($tmp);
|
||||
if (("$ref_max_age" !== $tmp) || ($ref_max_age < 300))
|
||||
throw new InvalidParam('ref_max_age', "Has to be >=300.");
|
||||
$tmp = $request->get_parameter('ref_max_age');
|
||||
if ($tmp === null) $tmp = "300";
|
||||
if ($tmp == "nolimit") $tmp = "9999999";
|
||||
$ref_max_age = intval($tmp);
|
||||
if (("$ref_max_age" !== $tmp) || ($ref_max_age < 300))
|
||||
throw new InvalidParam('ref_max_age', "Has to be >=300.");
|
||||
|
||||
# Search params.
|
||||
# Search params.
|
||||
|
||||
$search_params = SearchAssistant::get_common_search_params($request);
|
||||
$tables = array_merge(
|
||||
array('caches'),
|
||||
$search_params['extra_tables']
|
||||
);
|
||||
$where_conds = array_merge(
|
||||
array('caches.wp_oc is not null'),
|
||||
$search_params['where_conds']
|
||||
);
|
||||
unset($search_params);
|
||||
$search_assistant = new SearchAssistant($request);
|
||||
$search_assistant->prepare_common_search_params();
|
||||
$search_params = $search_assistant->get_search_params();
|
||||
$tables = array_merge(
|
||||
array('caches'),
|
||||
$search_params['extra_tables']
|
||||
);
|
||||
$where_conds = array_merge(
|
||||
array('caches.wp_oc is not null'),
|
||||
$search_params['where_conds']
|
||||
);
|
||||
unset($search_params);
|
||||
|
||||
# Generate, or retrieve an existing set, and return the result.
|
||||
# All user-supplied data in $tables and $where_conds MUST be escaped!
|
||||
# Generate, or retrieve an existing set, and return the result.
|
||||
# All user-supplied data in $tables and $where_conds MUST be escaped!
|
||||
|
||||
$result = self::get_set($tables, $where_conds, $min_store, $ref_max_age);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$result = self::get_set($tables, $where_conds, $min_store, $ref_max_age);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Important: YOU HAVE TO make sure $tables and $where_conds don't contain
|
||||
* unescaped user-supplied data!
|
||||
*/
|
||||
public static function get_set($tables, $where_conds, $min_store, $ref_max_age)
|
||||
{
|
||||
# Compute the "params hash".
|
||||
/**
|
||||
* Important: YOU HAVE TO make sure $tables and $where_conds don't contain
|
||||
* unescaped user-supplied data!
|
||||
*/
|
||||
public static function get_set($tables, $where_conds, $min_store, $ref_max_age)
|
||||
{
|
||||
# Compute the "params hash".
|
||||
|
||||
$params_hash = md5(serialize(array($tables, $where_conds)));
|
||||
$params_hash = md5(serialize(array($tables, $where_conds)));
|
||||
|
||||
# Check if there exists an entry for this hash, which also meets the
|
||||
# given freshness criteria.
|
||||
# Check if there exists an entry for this hash, which also meets the
|
||||
# given freshness criteria.
|
||||
|
||||
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
||||
if ($set_id === null)
|
||||
{
|
||||
# To avoid generating the same results by multiple threads at once
|
||||
# (the "tile" method uses the "save" method, so the problem is
|
||||
# quite real!), we will acquire a write-lock here.
|
||||
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
||||
if ($set_id === null)
|
||||
{
|
||||
# To avoid generating the same results by multiple threads at once
|
||||
# (the "tile" method uses the "save" method, so the problem is
|
||||
# quite real!), we will acquire a write-lock here.
|
||||
|
||||
$lock = OkapiLock::get("search-results-writer");
|
||||
$lock->acquire();
|
||||
$lock = OkapiLock::get("search-results-writer");
|
||||
$lock->acquire();
|
||||
|
||||
try
|
||||
{
|
||||
# Make sure we were the first to acquire the lock.
|
||||
try
|
||||
{
|
||||
# Make sure we were the first to acquire the lock.
|
||||
|
||||
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
||||
if ($set_id === null)
|
||||
{
|
||||
# We are in the first thread which have acquired the lock.
|
||||
# We will proceed with result-set creation. Other threads
|
||||
# will be waiting until we finish.
|
||||
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
||||
if ($set_id === null)
|
||||
{
|
||||
# We are in the first thread which have acquired the lock.
|
||||
# We will proceed with result-set creation. Other threads
|
||||
# will be waiting until we finish.
|
||||
|
||||
Db::execute("
|
||||
insert into okapi_search_sets (params_hash, date_created, expires)
|
||||
values (
|
||||
'processing in progress',
|
||||
now(),
|
||||
date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
||||
)
|
||||
");
|
||||
$set_id = Db::last_insert_id();
|
||||
$date_created = time();
|
||||
$expires = $date_created + $min_store + 60;
|
||||
Db::execute("
|
||||
insert into okapi_search_results (set_id, cache_id)
|
||||
select distinct
|
||||
'".mysql_real_escape_string($set_id)."',
|
||||
caches.cache_id
|
||||
from ".implode(", ", $tables)."
|
||||
where (".implode(") and (", $where_conds).")
|
||||
");
|
||||
Db::execute("
|
||||
insert into okapi_search_sets (params_hash, date_created, expires)
|
||||
values (
|
||||
'processing in progress',
|
||||
now(),
|
||||
date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
||||
)
|
||||
");
|
||||
$set_id = Db::last_insert_id();
|
||||
$date_created = time();
|
||||
$expires = $date_created + $min_store + 60;
|
||||
Db::execute("
|
||||
insert into okapi_search_results (set_id, cache_id)
|
||||
select distinct
|
||||
'".mysql_real_escape_string($set_id)."',
|
||||
caches.cache_id
|
||||
from ".implode(", ", $tables)."
|
||||
where (".implode(") and (", $where_conds).")
|
||||
");
|
||||
|
||||
# Lock barrier, to make sure the data is visible by other
|
||||
# sessions. See http://bugs.mysql.com/bug.php?id=36618
|
||||
# Lock barrier, to make sure the data is visible by other
|
||||
# sessions. See http://bugs.mysql.com/bug.php?id=36618
|
||||
|
||||
Db::execute("lock table okapi_search_results write");
|
||||
Db::execute("unlock tables");
|
||||
Db::execute("lock table okapi_search_results write");
|
||||
Db::execute("unlock tables");
|
||||
|
||||
Db::execute("
|
||||
update okapi_search_sets
|
||||
set params_hash = '".mysql_real_escape_string($params_hash)."'
|
||||
where id = '".mysql_real_escape_string($set_id)."'
|
||||
");
|
||||
} else {
|
||||
# Some other thread acquired the lock before us and it has
|
||||
# generated the result set. We don't need to do anything.
|
||||
}
|
||||
$lock->release();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# SQL error? Make sure the lock is released and rethrow.
|
||||
Db::execute("
|
||||
update okapi_search_sets
|
||||
set params_hash = '".mysql_real_escape_string($params_hash)."'
|
||||
where id = '".mysql_real_escape_string($set_id)."'
|
||||
");
|
||||
} else {
|
||||
# Some other thread acquired the lock before us and it has
|
||||
# generated the result set. We don't need to do anything.
|
||||
}
|
||||
$lock->release();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# SQL error? Make sure the lock is released and rethrow.
|
||||
|
||||
$lock->release();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
$lock->release();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
# If we got an old set, we may need to expand its lifetime in order to
|
||||
# meet user's "min_store" criterium.
|
||||
# If we got an old set, we may need to expand its lifetime in order to
|
||||
# meet user's "min_store" criterium.
|
||||
|
||||
if (time() + $min_store > $expires)
|
||||
{
|
||||
Db::execute("
|
||||
update okapi_search_sets
|
||||
set expires = date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
||||
where id = '".mysql_real_escape_string($set_id)."'
|
||||
");
|
||||
}
|
||||
if (time() + $min_store > $expires)
|
||||
{
|
||||
Db::execute("
|
||||
update okapi_search_sets
|
||||
set expires = date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
||||
where id = '".mysql_real_escape_string($set_id)."'
|
||||
");
|
||||
}
|
||||
|
||||
return array(
|
||||
'set_id' => "$set_id",
|
||||
'generated_at' => date('c', $date_created),
|
||||
'expires' => date('c', $expires),
|
||||
);
|
||||
}
|
||||
return array(
|
||||
'set_id' => "$set_id",
|
||||
'generated_at' => date('c', $date_created),
|
||||
'expires' => date('c', $expires),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,36 @@
|
||||
<xml>
|
||||
<brief>Save a search result set</brief>
|
||||
<issue-id>163</issue-id>
|
||||
<desc>
|
||||
<p>This works similar to the <b>search/all</b> method, but the returned
|
||||
set of geocaches is temporarilly stored, instead of being directly
|
||||
returned to you.</p>
|
||||
<p>You may want to use this method when you don't want your search
|
||||
results modified while the user is browsing through them, page by page.
|
||||
To view a portion of a saved search, use the <b>search/all</b>
|
||||
method with proper <b>set_and</b> <u>and <b>status</b></u> (!)
|
||||
parameters.</p>
|
||||
</desc>
|
||||
<opt name='min_store' default="300">
|
||||
The amount of time (in seconds) after which you allow OKAPI to delete
|
||||
the set (OKAPI <b>may</b> remove it, but doesn't have to).
|
||||
The maximum allowed value is 64800 (18 hours).
|
||||
</opt>
|
||||
<opt name='ref_max_age' default="300">
|
||||
<p>If OKAPI finds an existing result set which was created for your
|
||||
search query, it may return the ID of this existing set (and possibly
|
||||
extend its lifetime so it fits your <b>min_store</b>). What is the
|
||||
maximum age of the existing result set which you are willing to accept?</p>
|
||||
<p>This should be an integer (in seconds) <b>or</b> a special
|
||||
<b>nolimit</b> value. It must be greater or equal to 300 (5 minutes).</p>
|
||||
</opt>
|
||||
<import-params method='services/caches/search/all' except="offset|limit|order_by"/>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>set_id</b> - string, the identifier of your saved set,
|
||||
for future reference.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Save a search result set</brief>
|
||||
<issue-id>163</issue-id>
|
||||
<desc>
|
||||
<p>This works similar to the <b>search/all</b> method, but the returned
|
||||
set of geocaches is temporarilly stored, instead of being directly
|
||||
returned to you.</p>
|
||||
<p>You may want to use this method when you don't want your search
|
||||
results modified while the user is browsing through them, page by page.
|
||||
To view a portion of a saved search, use the <b>search/all</b>
|
||||
method with proper <b>set_and</b> <u>and <b>status</b></u> (!)
|
||||
parameters.</p>
|
||||
</desc>
|
||||
<opt name='min_store' default="300">
|
||||
The amount of time (in seconds) after which you allow OKAPI to delete
|
||||
the set (OKAPI <b>may</b> remove it, but doesn't have to).
|
||||
The maximum allowed value is 64800 (18 hours).
|
||||
</opt>
|
||||
<opt name='ref_max_age' default="300">
|
||||
<p>If OKAPI finds an existing result set which was created for your
|
||||
search query, it may return the ID of this existing set (and possibly
|
||||
extend its lifetime so it fits your <b>min_store</b>). What is the
|
||||
maximum age of the existing result set which you are willing to accept?</p>
|
||||
<p>This should be an integer (in seconds) <b>or</b> a special
|
||||
<b>nolimit</b> value. It must be greater or equal to 300 (5 minutes).</p>
|
||||
</opt>
|
||||
<import-params method='services/caches/search/all' except="offset|limit|order_by"/>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>set_id</b> - string, the identifier of your saved set,
|
||||
for future reference.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,109 +13,109 @@ use okapi\BadRequest;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Check search method
|
||||
$search_method = $request->get_parameter('search_method');
|
||||
if (!$search_method)
|
||||
throw new ParamMissing('search_method');
|
||||
if (strpos($search_method, "services/caches/search/") !== 0)
|
||||
throw new InvalidParam('search_method', "Should begin with 'services/caches/search/'.");
|
||||
if (!OkapiServiceRunner::exists($search_method))
|
||||
throw new InvalidParam('search_method', "Method does not exist: '$search_method'");
|
||||
$search_params = $request->get_parameter('search_params');
|
||||
if (!$search_params)
|
||||
throw new ParamMissing('search_params');
|
||||
$search_params = json_decode($search_params, true);
|
||||
if (!is_array($search_params))
|
||||
throw new InvalidParam('search_params', "Should be a JSON-encoded dictionary");
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Check search method
|
||||
$search_method = $request->get_parameter('search_method');
|
||||
if (!$search_method)
|
||||
throw new ParamMissing('search_method');
|
||||
if (strpos($search_method, "services/caches/search/") !== 0)
|
||||
throw new InvalidParam('search_method', "Should begin with 'services/caches/search/'.");
|
||||
if (!OkapiServiceRunner::exists($search_method))
|
||||
throw new InvalidParam('search_method', "Method does not exist: '$search_method'");
|
||||
$search_params = $request->get_parameter('search_params');
|
||||
if (!$search_params)
|
||||
throw new ParamMissing('search_params');
|
||||
$search_params = json_decode($search_params, true);
|
||||
if (!is_array($search_params))
|
||||
throw new InvalidParam('search_params', "Should be a JSON-encoded dictionary");
|
||||
|
||||
# Check retrieval method
|
||||
$retr_method = $request->get_parameter('retr_method');
|
||||
if (!$retr_method)
|
||||
throw new ParamMissing('retr_method');
|
||||
if (!OkapiServiceRunner::exists($retr_method))
|
||||
throw new InvalidParam('retr_method', "Method does not exist: '$retr_method'");
|
||||
$retr_params = $request->get_parameter('retr_params');
|
||||
if (!$retr_params)
|
||||
throw new ParamMissing('retr_params');
|
||||
$retr_params = json_decode($retr_params, true);
|
||||
if (!is_array($retr_params))
|
||||
throw new InvalidParam('retr_params', "Should be a JSON-encoded dictionary");
|
||||
# Check retrieval method
|
||||
$retr_method = $request->get_parameter('retr_method');
|
||||
if (!$retr_method)
|
||||
throw new ParamMissing('retr_method');
|
||||
if (!OkapiServiceRunner::exists($retr_method))
|
||||
throw new InvalidParam('retr_method', "Method does not exist: '$retr_method'");
|
||||
$retr_params = $request->get_parameter('retr_params');
|
||||
if (!$retr_params)
|
||||
throw new ParamMissing('retr_params');
|
||||
$retr_params = json_decode($retr_params, true);
|
||||
if (!is_array($retr_params))
|
||||
throw new InvalidParam('retr_params', "Should be a JSON-encoded dictionary");
|
||||
|
||||
self::map_values_to_strings($search_params);
|
||||
self::map_values_to_strings($retr_params);
|
||||
self::map_values_to_strings($search_params);
|
||||
self::map_values_to_strings($retr_params);
|
||||
|
||||
# Wrapped?
|
||||
$wrap = $request->get_parameter('wrap');
|
||||
if ($wrap == null) throw new ParamMissing('wrap');
|
||||
if (!in_array($wrap, array('true', 'false')))
|
||||
throw new InvalidParam('wrap');
|
||||
$wrap = ($wrap == 'true');
|
||||
# Wrapped?
|
||||
$wrap = $request->get_parameter('wrap');
|
||||
if ($wrap == null) throw new ParamMissing('wrap');
|
||||
if (!in_array($wrap, array('true', 'false')))
|
||||
throw new InvalidParam('wrap');
|
||||
$wrap = ($wrap == 'true');
|
||||
|
||||
# Run search method
|
||||
try
|
||||
{
|
||||
$search_result = OkapiServiceRunner::call($search_method, new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, $search_params));
|
||||
}
|
||||
catch (BadRequest $e)
|
||||
{
|
||||
throw new InvalidParam('search_params', "Search method responded with the ".
|
||||
"following error message: ".$e->getMessage());
|
||||
}
|
||||
# Run search method
|
||||
try
|
||||
{
|
||||
$search_result = OkapiServiceRunner::call($search_method, new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, $search_params));
|
||||
}
|
||||
catch (BadRequest $e)
|
||||
{
|
||||
throw new InvalidParam('search_params', "Search method responded with the ".
|
||||
"following error message: ".$e->getMessage());
|
||||
}
|
||||
|
||||
# Run retrieval method
|
||||
try
|
||||
{
|
||||
$retr_result = OkapiServiceRunner::call($retr_method, new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array_merge($retr_params,
|
||||
array('cache_codes' => implode("|", $search_result['results'])))));
|
||||
}
|
||||
catch (BadRequest $e)
|
||||
{
|
||||
throw new InvalidParam('retr_params', "Retrieval method responded with the ".
|
||||
"following error message: ".$e->getMessage());
|
||||
}
|
||||
# Run retrieval method
|
||||
try
|
||||
{
|
||||
$retr_result = OkapiServiceRunner::call($retr_method, new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array_merge($retr_params,
|
||||
array('cache_codes' => implode("|", $search_result['results'])))));
|
||||
}
|
||||
catch (BadRequest $e)
|
||||
{
|
||||
throw new InvalidParam('retr_params', "Retrieval method responded with the ".
|
||||
"following error message: ".$e->getMessage());
|
||||
}
|
||||
|
||||
if ($wrap)
|
||||
{
|
||||
# $retr_result might be a PHP object, but also might be a binary response
|
||||
# (e.g. a GPX file).
|
||||
if ($retr_result instanceof OkapiHttpResponse)
|
||||
$result = array('results' => $retr_result->get_body());
|
||||
else
|
||||
$result = array('results' => $retr_result);
|
||||
foreach ($search_result as $key => &$value_ref)
|
||||
if ($key != 'results')
|
||||
$result[$key] = $value_ref;
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($retr_result instanceof OkapiHttpResponse)
|
||||
return $retr_result;
|
||||
else
|
||||
return Okapi::formatted_response($request, $retr_result);
|
||||
}
|
||||
}
|
||||
if ($wrap)
|
||||
{
|
||||
# $retr_result might be a PHP object, but also might be a binary response
|
||||
# (e.g. a GPX file).
|
||||
if ($retr_result instanceof OkapiHttpResponse)
|
||||
$result = array('results' => $retr_result->get_body());
|
||||
else
|
||||
$result = array('results' => $retr_result);
|
||||
foreach ($search_result as $key => &$value_ref)
|
||||
if ($key != 'results')
|
||||
$result[$key] = $value_ref;
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($retr_result instanceof OkapiHttpResponse)
|
||||
return $retr_result;
|
||||
else
|
||||
return Okapi::formatted_response($request, $retr_result);
|
||||
}
|
||||
}
|
||||
|
||||
private static function map_values_to_strings(&$dict)
|
||||
{
|
||||
foreach (array_keys($dict) as $key)
|
||||
{
|
||||
$val = $dict[$key];
|
||||
if (is_numeric($val) || is_string($val))
|
||||
$dict[$key] = (string)$val;
|
||||
else
|
||||
throw new BadRequest("Invalid value format for key: ".$key);
|
||||
}
|
||||
}
|
||||
private static function map_values_to_strings(&$dict)
|
||||
{
|
||||
foreach (array_keys($dict) as $key)
|
||||
{
|
||||
$val = $dict[$key];
|
||||
if (is_numeric($val) || is_string($val))
|
||||
$dict[$key] = (string)$val;
|
||||
else
|
||||
throw new BadRequest("Invalid value format for key: ".$key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +1,65 @@
|
||||
<xml>
|
||||
<brief>Search for caches and retrieve formatted results</brief>
|
||||
<issue-id>18</issue-id>
|
||||
<desc>
|
||||
<p>We think that searching and retrieving data are two different things
|
||||
and that's why they were cleanly separated in the documentation (put in
|
||||
separate methods). This was done primarily to keep the docs clean.
|
||||
This method allows you to do a quick search+retrieve task in one request.</p>
|
||||
<p>All services/caches/search/* methods respond with a list of cache codes.
|
||||
Then you have to use other method (like services/caches/geocaches) to
|
||||
retrieve the names and locations, based on those cache codes. The
|
||||
<b>search_and_retrieve</b> method allows you to do these two steps in one
|
||||
method call.</p>
|
||||
<p>First, you have to choose both methods and their parameters - one method
|
||||
which returns the cache codes, and the other one, that responds
|
||||
with additional data for the given caches.</p>
|
||||
</desc>
|
||||
<req name='search_method'>
|
||||
<p>Name of the search method (begin with "services/").</p>
|
||||
<p>E.g. <i>services/caches/search/nearest</i>.</p>
|
||||
</req>
|
||||
<req name='search_params'>
|
||||
<p>JSON-formatted dictionary of parameters to be passed on
|
||||
to the search method.</p>
|
||||
<p>E.g. <i>{"center": "49|19", "status": "Available"}</i>.</p>
|
||||
</req>
|
||||
<req name='retr_method'>
|
||||
<p>Name of the retrieval method (begin with "services/").</p>
|
||||
<p>E.g. <i>services/caches/geocaches</i>.</p>
|
||||
</req>
|
||||
<req name='retr_params'>
|
||||
<p>JSON-formatted dictionary of parameters to be passed on
|
||||
to the retrieval method.</p>
|
||||
<p>E.g. <i>{"fields": "name|location|type"}</i></p>
|
||||
<p>The method will be called with one additional parameter - <b>cache_codes</b>.
|
||||
These will be the cache codes collected from the results of the search method.</p>
|
||||
</req>
|
||||
<req name='wrap'>
|
||||
<p>Boolean.</p>
|
||||
<ul>
|
||||
<li>If <b>true</b>, then results will be wrapped in an additional
|
||||
object, in order to include any additional data received along with the
|
||||
search_method response (i.e. the <b>more</b> value).</li>
|
||||
<li>If <b>false</b>, then this method will return exactly what the
|
||||
<b>retr_method</b> will respond with.</li>
|
||||
</ul>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>If <b>wrap</b> is <b>true</b>, then the method will return a
|
||||
dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>results</b> - anything the retrival method
|
||||
responds with (as long as it's not an error).</li>
|
||||
<li>any extra keys and values received as a response of
|
||||
the search_method (i.e. the <b>more</b> variable).</li>
|
||||
</ul>
|
||||
<p>If <b>wrap</b> is <b>false</b>, then the method will return
|
||||
anything the retrieval methods responds with (along with its HTTP headers).</p>
|
||||
<p><b>Example:</b></p>
|
||||
<pre>search_and_retrieve<br/>?search_method=services/caches/search/bbox<br/>&search_params={"bbox":"49|19|50|20","limit":"1"}<br/>&retr_method=services/caches/geocaches<br/>&retr_params={"fields":"location"}<br/>&wrap=false</pre>
|
||||
<p>Possible output:<br/><code>{"OP205A": {"location": "49.572417|19.525867"}}</code></p>
|
||||
<p>The same example with <i>wrap=true</i> would return:<br/><code>{"results": {"OP205A": {"location": "49.572417|19.525867"}}, "more": true}</code></p>
|
||||
</returns>
|
||||
<brief>Search for caches and retrieve formatted results</brief>
|
||||
<issue-id>18</issue-id>
|
||||
<desc>
|
||||
<p>We think that searching and retrieving data are two different things
|
||||
and that's why they were cleanly separated in the documentation (put in
|
||||
separate methods). This was done primarily to keep the docs clean.
|
||||
This method allows you to do a quick search+retrieve task in one request.</p>
|
||||
<p>All services/caches/search/* methods respond with a list of cache codes.
|
||||
Then you have to use other method (like services/caches/geocaches) to
|
||||
retrieve the names and locations, based on those cache codes. The
|
||||
<b>search_and_retrieve</b> method allows you to do these two steps in one
|
||||
method call.</p>
|
||||
<p>First, you have to choose both methods and their parameters - one method
|
||||
which returns the cache codes, and the other one, that responds
|
||||
with additional data for the given caches.</p>
|
||||
</desc>
|
||||
<req name='search_method'>
|
||||
<p>Name of the search method (begin with "services/").</p>
|
||||
<p>E.g. <i>services/caches/search/nearest</i>.</p>
|
||||
</req>
|
||||
<req name='search_params'>
|
||||
<p>JSON-formatted dictionary of parameters to be passed on
|
||||
to the search method.</p>
|
||||
<p>E.g. <i>{"center": "49|19", "status": "Available"}</i>.</p>
|
||||
</req>
|
||||
<req name='retr_method'>
|
||||
<p>Name of the retrieval method (begin with "services/").</p>
|
||||
<p>E.g. <i>services/caches/geocaches</i>.</p>
|
||||
</req>
|
||||
<req name='retr_params'>
|
||||
<p>JSON-formatted dictionary of parameters to be passed on
|
||||
to the retrieval method.</p>
|
||||
<p>E.g. <i>{"fields": "name|location|type"}</i></p>
|
||||
<p>The method will be called with one additional parameter - <b>cache_codes</b>.
|
||||
These will be the cache codes collected from the results of the search method.</p>
|
||||
</req>
|
||||
<req name='wrap'>
|
||||
<p>Boolean.</p>
|
||||
<ul>
|
||||
<li>If <b>true</b>, then results will be wrapped in an additional
|
||||
object, in order to include any additional data received along with the
|
||||
search_method response (i.e. the <b>more</b> value).</li>
|
||||
<li>If <b>false</b>, then this method will return exactly what the
|
||||
<b>retr_method</b> will respond with.</li>
|
||||
</ul>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>If <b>wrap</b> is <b>true</b>, then the method will return a
|
||||
dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>results</b> - anything the retrival method
|
||||
responds with (as long as it's not an error).</li>
|
||||
<li>any extra keys and values received as a response of
|
||||
the search_method (i.e. the <b>more</b> variable).</li>
|
||||
</ul>
|
||||
<p>If <b>wrap</b> is <b>false</b>, then the method will return
|
||||
anything the retrieval methods responds with (along with its HTTP headers).</p>
|
||||
<p><b>Example:</b></p>
|
||||
<pre>search_and_retrieve<br/>?search_method=services/caches/search/bbox<br/>&search_params={"bbox":"49|19|50|20","limit":"1"}<br/>&retr_method=services/caches/geocaches<br/>&retr_params={"fields":"location"}<br/>&wrap=false</pre>
|
||||
<p>Possible output:<br/><code>{"OP205A": {"location": "49.572417|19.525867"}}</code></p>
|
||||
<p>The same example with <i>wrap=true</i> would return:<br/><code>{"results": {"OP205A": {"location": "49.572417|19.525867"}}, "more": true}</code></p>
|
||||
</returns>
|
||||
</xml>
|
@ -15,149 +15,149 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
private static $valid_field_names = array(
|
||||
'uuid', 'cache_code', 'date', 'user', 'type', 'was_recommended', 'comment',
|
||||
'images', 'internal_id', 'oc_team_entry',
|
||||
);
|
||||
private static $valid_field_names = array(
|
||||
'uuid', 'cache_code', 'date', 'user', 'type', 'was_recommended', 'comment',
|
||||
'images', 'internal_id', 'oc_team_entry',
|
||||
);
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$log_uuids = $request->get_parameter('log_uuids');
|
||||
if ($log_uuids === null) throw new ParamMissing('log_uuids');
|
||||
if ($log_uuids === "")
|
||||
{
|
||||
$log_uuids = array();
|
||||
}
|
||||
else
|
||||
$log_uuids = explode("|", $log_uuids);
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$log_uuids = $request->get_parameter('log_uuids');
|
||||
if ($log_uuids === null) throw new ParamMissing('log_uuids');
|
||||
if ($log_uuids === "")
|
||||
{
|
||||
$log_uuids = array();
|
||||
}
|
||||
else
|
||||
$log_uuids = explode("|", $log_uuids);
|
||||
|
||||
if ((count($log_uuids) > 500) && (!$request->skip_limits))
|
||||
throw new InvalidParam('log_uuids', "Maximum allowed number of referenced ".
|
||||
"log entries is 500. You provided ".count($log_uuids)." UUIDs.");
|
||||
if (count($log_uuids) != count(array_unique($log_uuids)))
|
||||
throw new InvalidParam('log_uuids', "Duplicate UUIDs detected (make sure each UUID is referenced only once).");
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "date|user|type|comment";
|
||||
$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.");
|
||||
if ((count($log_uuids) > 500) && (!$request->skip_limits))
|
||||
throw new InvalidParam('log_uuids', "Maximum allowed number of referenced ".
|
||||
"log entries is 500. You provided ".count($log_uuids)." UUIDs.");
|
||||
if (count($log_uuids) != count(array_unique($log_uuids)))
|
||||
throw new InvalidParam('log_uuids', "Duplicate UUIDs detected (make sure each UUID is referenced only once).");
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "date|user|type|comment";
|
||||
$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.");
|
||||
|
||||
if (Settings::get('OC_BRANCH') == 'oc.de')
|
||||
{
|
||||
$teamentry_field = 'cl.oc_team_comment';
|
||||
$ratingdate_condition = 'and cr.rating_date=cl.date';
|
||||
}
|
||||
else
|
||||
{
|
||||
$teamentry_field = '(cl.type=12)';
|
||||
$ratingdate_condition = '';
|
||||
}
|
||||
$rs = Db::query("
|
||||
select
|
||||
cl.id, c.wp_oc as cache_code, cl.uuid, cl.type,
|
||||
".$teamentry_field." as oc_team_entry,
|
||||
unix_timestamp(cl.date) as date, cl.text,
|
||||
u.uuid as user_uuid, u.username, u.user_id,
|
||||
if(cr.user_id is null, 0, 1) as was_recommended
|
||||
from
|
||||
(cache_logs cl,
|
||||
user u,
|
||||
caches c)
|
||||
left join cache_rating cr
|
||||
on cr.user_id = u.user_id
|
||||
and cr.cache_id = c.cache_id
|
||||
".$ratingdate_condition."
|
||||
and cl.type in (
|
||||
".Okapi::logtypename2id("Found it").",
|
||||
".Okapi::logtypename2id("Attended")."
|
||||
)
|
||||
where
|
||||
cl.uuid in ('".implode("','", array_map('mysql_real_escape_string', $log_uuids))."')
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
||||
and cl.user_id = u.user_id
|
||||
and c.cache_id = cl.cache_id
|
||||
and c.status in (1,2,3)
|
||||
");
|
||||
$results = array();
|
||||
$log_id2uuid = array(); /* Maps logs' internal_ids to uuids */
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$results[$row['uuid']] = array(
|
||||
'uuid' => $row['uuid'],
|
||||
'cache_code' => $row['cache_code'],
|
||||
'date' => date('c', $row['date']),
|
||||
'user' => array(
|
||||
'uuid' => $row['user_uuid'],
|
||||
'username' => $row['username'],
|
||||
'profile_url' => Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id'],
|
||||
),
|
||||
'type' => Okapi::logtypeid2name($row['type']),
|
||||
'was_recommended' => $row['was_recommended'] ? true : false,
|
||||
'comment' => Okapi::fix_oc_html($row['text']),
|
||||
'images' => array(),
|
||||
'internal_id' => $row['id'],
|
||||
);
|
||||
if (in_array('oc_team_entry',$fields))
|
||||
$results[$row['uuid']]['oc_team_entry'] = $row['oc_team_entry'] ? true : false;
|
||||
$log_id2uuid[$row['id']] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
if (Settings::get('OC_BRANCH') == 'oc.de')
|
||||
{
|
||||
$teamentry_field = 'cl.oc_team_comment';
|
||||
$ratingdate_condition = 'and cr.rating_date=cl.date';
|
||||
}
|
||||
else
|
||||
{
|
||||
$teamentry_field = '(cl.type=12)';
|
||||
$ratingdate_condition = '';
|
||||
}
|
||||
$rs = Db::query("
|
||||
select
|
||||
cl.id, c.wp_oc as cache_code, cl.uuid, cl.type,
|
||||
".$teamentry_field." as oc_team_entry,
|
||||
unix_timestamp(cl.date) as date, cl.text,
|
||||
u.uuid as user_uuid, u.username, u.user_id,
|
||||
if(cr.user_id is null, 0, 1) as was_recommended
|
||||
from
|
||||
(cache_logs cl,
|
||||
user u,
|
||||
caches c)
|
||||
left join cache_rating cr
|
||||
on cr.user_id = u.user_id
|
||||
and cr.cache_id = c.cache_id
|
||||
".$ratingdate_condition."
|
||||
and cl.type in (
|
||||
".Okapi::logtypename2id("Found it").",
|
||||
".Okapi::logtypename2id("Attended")."
|
||||
)
|
||||
where
|
||||
cl.uuid in ('".implode("','", array_map('mysql_real_escape_string', $log_uuids))."')
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
||||
and cl.user_id = u.user_id
|
||||
and c.cache_id = cl.cache_id
|
||||
and c.status in (1,2,3)
|
||||
");
|
||||
$results = array();
|
||||
$log_id2uuid = array(); /* Maps logs' internal_ids to uuids */
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$results[$row['uuid']] = array(
|
||||
'uuid' => $row['uuid'],
|
||||
'cache_code' => $row['cache_code'],
|
||||
'date' => date('c', $row['date']),
|
||||
'user' => array(
|
||||
'uuid' => $row['user_uuid'],
|
||||
'username' => $row['username'],
|
||||
'profile_url' => Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id'],
|
||||
),
|
||||
'type' => Okapi::logtypeid2name($row['type']),
|
||||
'was_recommended' => $row['was_recommended'] ? true : false,
|
||||
'comment' => Okapi::fix_oc_html($row['text']),
|
||||
'images' => array(),
|
||||
'internal_id' => $row['id'],
|
||||
);
|
||||
if (in_array('oc_team_entry',$fields))
|
||||
$results[$row['uuid']]['oc_team_entry'] = $row['oc_team_entry'] ? true : false;
|
||||
$log_id2uuid[$row['id']] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
# fetch images
|
||||
# fetch images
|
||||
|
||||
if (in_array('images', $fields))
|
||||
{
|
||||
$rs = Db::query("
|
||||
select object_id, uuid, url, title, spoiler
|
||||
from pictures
|
||||
where
|
||||
object_type = 1
|
||||
and object_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($log_id2uuid)))."')
|
||||
and display = 1 /* currently is always 1 for logpix */
|
||||
and unknown_format = 0
|
||||
order by date_created
|
||||
");
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$results[$log_id2uuid[$row['object_id']]]['images'][] =
|
||||
array(
|
||||
'uuid' => $row['uuid'],
|
||||
'url' => $row['url'],
|
||||
'thumb_url' => Settings::get('SITE_URL') . 'thumbs.php?uuid=' . $row['uuid'],
|
||||
'caption' => $row['title'],
|
||||
'is_spoiler' => ($row['spoiler'] ? true : false),
|
||||
);
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
}
|
||||
if (in_array('images', $fields))
|
||||
{
|
||||
$rs = Db::query("
|
||||
select object_id, uuid, url, title, spoiler
|
||||
from pictures
|
||||
where
|
||||
object_type = 1
|
||||
and object_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($log_id2uuid)))."')
|
||||
and display = 1 /* currently is always 1 for logpix */
|
||||
and unknown_format = 0
|
||||
order by date_created
|
||||
");
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$results[$log_id2uuid[$row['object_id']]]['images'][] =
|
||||
array(
|
||||
'uuid' => $row['uuid'],
|
||||
'url' => $row['url'],
|
||||
'thumb_url' => Settings::get('SITE_URL') . 'thumbs.php?uuid=' . $row['uuid'],
|
||||
'caption' => $row['title'],
|
||||
'is_spoiler' => ($row['spoiler'] ? true : false),
|
||||
);
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
}
|
||||
|
||||
# Check which UUIDs were not found and mark them with null.
|
||||
# Check which UUIDs were not found and mark them with null.
|
||||
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
if (!isset($results[$log_uuid]))
|
||||
$results[$log_uuid] = null;
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
if (!isset($results[$log_uuid]))
|
||||
$results[$log_uuid] = null;
|
||||
|
||||
# Remove unwanted fields.
|
||||
# Remove unwanted fields.
|
||||
|
||||
foreach (self::$valid_field_names as $field)
|
||||
if (!in_array($field, $fields))
|
||||
foreach ($results as &$result_ref)
|
||||
unset($result_ref[$field]);
|
||||
foreach (self::$valid_field_names as $field)
|
||||
if (!in_array($field, $fields))
|
||||
foreach ($results as &$result_ref)
|
||||
unset($result_ref[$field]);
|
||||
|
||||
# Order the results in the same order as the input codes were given.
|
||||
# Order the results in the same order as the input codes were given.
|
||||
|
||||
$ordered_results = array();
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
$ordered_results[$log_uuid] = $results[$log_uuid];
|
||||
$ordered_results = array();
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
$ordered_results[$log_uuid] = $results[$log_uuid];
|
||||
|
||||
return Okapi::formatted_response($request, $ordered_results);
|
||||
}
|
||||
return Okapi::formatted_response($request, $ordered_results);
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
<xml>
|
||||
<brief>Retrieve information on multiple log entries</brief>
|
||||
<issue-id>107</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the services/logs/entry method, but works
|
||||
with multiple log entries (instead of only one).</p>
|
||||
</desc>
|
||||
<req name='log_uuids'>
|
||||
<p>Pipe-separated list of UUIDs. These represent the log entries you
|
||||
are interested in. No more than 500 codes are allowed.
|
||||
Unlike in the "entry" method, this CAN be an empty string (it will
|
||||
result in an empty, but valid, response).</p>
|
||||
</req>
|
||||
<opt name='fields' default='date|user|type|comment'>
|
||||
<p>Same as in the services/logs/entry method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/logs/entry method for a list of available values.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. UUIDs you provide will be mapped to dictionary keys,
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given UUID haven't been found.
|
||||
(This behavior is different than in the services/logs/entry method, which
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
<brief>Retrieve information on multiple log entries</brief>
|
||||
<issue-id>107</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the services/logs/entry method, but works
|
||||
with multiple log entries (instead of only one).</p>
|
||||
</desc>
|
||||
<req name='log_uuids'>
|
||||
<p>Pipe-separated list of UUIDs. These represent the log entries you
|
||||
are interested in. No more than 500 codes are allowed.
|
||||
Unlike in the "entry" method, this CAN be an empty string (it will
|
||||
result in an empty, but valid, response).</p>
|
||||
</req>
|
||||
<opt name='fields' default='date|user|type|comment'>
|
||||
<p>Same as in the services/logs/entry method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/logs/entry method for a list of available values.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. UUIDs you provide will be mapped to dictionary keys,
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given UUID haven't been found.
|
||||
(This behavior is different than in the services/logs/entry method, which
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
</xml>
|
@ -11,26 +11,26 @@ use okapi\InvalidParam;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$log_uuid = $request->get_parameter('log_uuid');
|
||||
if (!$log_uuid) throw new ParamMissing('log_uuid');
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "date|user|type|comment";
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$log_uuid = $request->get_parameter('log_uuid');
|
||||
if (!$log_uuid) throw new ParamMissing('log_uuid');
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "date|user|type|comment";
|
||||
|
||||
$results = OkapiServiceRunner::call('services/logs/entries', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('log_uuids' => $log_uuid,
|
||||
'fields' => $fields)));
|
||||
$result = $results[$log_uuid];
|
||||
if ($result == null)
|
||||
throw new InvalidParam('log_uuid', "This log entry does not exist.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$results = OkapiServiceRunner::call('services/logs/entries', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('log_uuids' => $log_uuid,
|
||||
'fields' => $fields)));
|
||||
$result = $results[$log_uuid];
|
||||
if ($result == null)
|
||||
throw new InvalidParam('log_uuid', "This log entry does not exist.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,117 +1,117 @@
|
||||
<xml>
|
||||
<brief>Retrieve information on a single log entry</brief>
|
||||
<issue-id>108</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve information on a single log entry.</p>
|
||||
</desc>
|
||||
<req name='log_uuid'>UUID of the log entry</req>
|
||||
<opt name='fields' default='date|user|type|comment'>
|
||||
<p>Pipe-separated list of field names which you are interested with.
|
||||
Selected fields will be included in the response. See below fot the list
|
||||
of available fields.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>uuid</b> - unique ID of the log entry,</li>
|
||||
<li><b>cache_code</b> - code of the cache which the log entry refers to,</li>
|
||||
<li>
|
||||
<p><b>date</b> - date and time (ISO 8601) when the log entry was submitted.</p>
|
||||
<p>Please note that log entries often contain dates only (with the times
|
||||
truncated to midnight, as in the local timezone). In such cases, you may
|
||||
want to avoid displaying the time. You may assume that if the <b>date</b>
|
||||
value contains the "00:00:00" string, then it is date-only.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>user</b> - a dictionary:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - ID of the user (author of the log entry),</li>
|
||||
<li><b>username</b> - name of the user (who submitted the log entry),</li>
|
||||
<li><b>profile_url</b> - URL of the profile page of the user,</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>type</b> - string; log type. One of the values documented
|
||||
below.</p>
|
||||
|
||||
<p>Primary types, commonly used by all Opencaching installations:</p>
|
||||
|
||||
<ul>
|
||||
<li>"Found it" - a user found the cache (Non-Event caches).</li>
|
||||
<li>"Didn't find it" - a user searched for, but couldn't find the cache (Non-Event caches).</li>
|
||||
<li>"Comment".</li>
|
||||
<li>"Will attend" - a user is planning to attend the event (for Event caches only).</li>
|
||||
<li>"Attended" - a user has attended the event (for Event caches only).</li>
|
||||
</ul>
|
||||
|
||||
<p>Types which indicate a change of state of the geocache or confirm the
|
||||
current state (used only by some Opencaching installations):</p>
|
||||
|
||||
<ul>
|
||||
<li>"Temporarily unavailable" - probably the cache cannot be found,
|
||||
but it may be repaired (then, "Ready to search" will be submitted).</li>
|
||||
<li>"Ready to search" - the cache can be found again.</li>
|
||||
<li>"Archived" - the cache cannot be found and probably won't be
|
||||
repaired.</li>
|
||||
<li>"Locked" - the cache has been archived and can no longer be logged.</li>
|
||||
</ul>
|
||||
|
||||
<p>Other types (used only by some Opencaching installations):</p>
|
||||
|
||||
<ul>
|
||||
<li>"Needs maintenance" - a user states that the cache is
|
||||
in need of maintenance.</li>
|
||||
<li>"Maintenance performed" - the cache owner states that he
|
||||
had performed the maintenance.</li>
|
||||
<li>"Moved" - the cache has been moved to a different location.</li>
|
||||
<li>"OC Team comment" - a comment made by the official OC Team
|
||||
member.</li>
|
||||
<li><i>(to be continued)</i> - this list MAY expand in time!
|
||||
Your application should accept unknown log types (you may
|
||||
treat them as "Comment"s).</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>oc_team_entry</b> - <b>true</b> if the log entry has been made by an
|
||||
official OC team member and marked as administrative log; <b>false</b> if it has
|
||||
not been marked.</p>
|
||||
<p>Note: <b>false</b> does NOT mean that it is no administrative log,
|
||||
because this flag can be missing for (mostly old) admin logs.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>was_recommended</b> - <b>true</b>, if the author included his recommendation
|
||||
in this log entry,</p>
|
||||
</li>
|
||||
<li><b>comment</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>, text entered
|
||||
with the log entry,</li>
|
||||
<li>
|
||||
<p><b>images</b> - list of dictionaries, each dictionary represents one
|
||||
image saved along with the log; each dictionary has the following
|
||||
structure:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - UUID of the image,</li>
|
||||
<li><b>url</b> - URL of the image,</li>
|
||||
<li><b>thumb_url</b> - URL of a small (thumb) version of the image,</li>
|
||||
<li><b>caption</b> - plain-text string, caption of the image,</li>
|
||||
<li><b>is_spoiler</b> - boolean, if <b>true</b> then the image is
|
||||
a spoiler image and should not be displayed to the user unless
|
||||
the user explicitly asks for it.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>internal_id</b> - undocumented, you <u>should not</u> use
|
||||
this unless you really know you need to. Internal IDs are
|
||||
<b>not</b> unique across various OKAPI installations.
|
||||
Try to use UUIDs instead.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Note, that some fields can change in time (users can edit/delete
|
||||
their log entries).</p>
|
||||
|
||||
<p>If given log entry does not exist, the method will
|
||||
respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
<brief>Retrieve information on a single log entry</brief>
|
||||
<issue-id>108</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve information on a single log entry.</p>
|
||||
</desc>
|
||||
<req name='log_uuid'>UUID of the log entry</req>
|
||||
<opt name='fields' default='date|user|type|comment'>
|
||||
<p>Pipe-separated list of field names which you are interested with.
|
||||
Selected fields will be included in the response. See below fot the list
|
||||
of available fields.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>uuid</b> - unique ID of the log entry,</li>
|
||||
<li><b>cache_code</b> - code of the cache which the log entry refers to,</li>
|
||||
<li>
|
||||
<p><b>date</b> - date and time (ISO 8601) when the log entry was submitted.</p>
|
||||
<p>Please note that log entries often contain dates only (with the times
|
||||
truncated to midnight, as in the local timezone). In such cases, you may
|
||||
want to avoid displaying the time. You may assume that if the <b>date</b>
|
||||
value contains the "00:00:00" string, then it is date-only.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>user</b> - a dictionary:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - ID of the user (author of the log entry),</li>
|
||||
<li><b>username</b> - name of the user (who submitted the log entry),</li>
|
||||
<li><b>profile_url</b> - URL of the profile page of the user,</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>type</b> - string; log type. One of the values documented
|
||||
below.</p>
|
||||
|
||||
<p>Primary types, commonly used by all Opencaching installations:</p>
|
||||
|
||||
<ul>
|
||||
<li>"Found it" - a user found the cache (Non-Event caches).</li>
|
||||
<li>"Didn't find it" - a user searched for, but couldn't find the cache (Non-Event caches).</li>
|
||||
<li>"Comment".</li>
|
||||
<li>"Will attend" - a user is planning to attend the event (for Event caches only).</li>
|
||||
<li>"Attended" - a user has attended the event (for Event caches only).</li>
|
||||
</ul>
|
||||
|
||||
<p>Types which indicate a change of state of the geocache or confirm the
|
||||
current state (used only by some Opencaching installations):</p>
|
||||
|
||||
<ul>
|
||||
<li>"Temporarily unavailable" - probably the cache cannot be found,
|
||||
but it may be repaired (then, "Ready to search" will be submitted).</li>
|
||||
<li>"Ready to search" - the cache can be found again.</li>
|
||||
<li>"Archived" - the cache cannot be found and probably won't be
|
||||
repaired.</li>
|
||||
<li>"Locked" - the cache has been archived and can no longer be logged.</li>
|
||||
</ul>
|
||||
|
||||
<p>Other types (used only by some Opencaching installations):</p>
|
||||
|
||||
<ul>
|
||||
<li>"Needs maintenance" - a user states that the cache is
|
||||
in need of maintenance.</li>
|
||||
<li>"Maintenance performed" - the cache owner states that he
|
||||
had performed the maintenance.</li>
|
||||
<li>"Moved" - the cache has been moved to a different location.</li>
|
||||
<li>"OC Team comment" - a comment made by the official OC Team
|
||||
member.</li>
|
||||
<li><i>(to be continued)</i> - this list MAY expand in time!
|
||||
Your application should accept unknown log types (you may
|
||||
treat them as "Comment"s).</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>oc_team_entry</b> - <b>true</b> if the log entry has been made by an
|
||||
official OC team member and marked as administrative log; <b>false</b> if it has
|
||||
not been marked.</p>
|
||||
<p>Note: <b>false</b> does NOT mean that it is no administrative log,
|
||||
because this flag can be missing for (mostly old) admin logs.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>was_recommended</b> - <b>true</b>, if the author included his recommendation
|
||||
in this log entry,</p>
|
||||
</li>
|
||||
<li><b>comment</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>, text entered
|
||||
with the log entry,</li>
|
||||
<li>
|
||||
<p><b>images</b> - list of dictionaries, each dictionary represents one
|
||||
image saved along with the log; each dictionary has the following
|
||||
structure:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - UUID of the image,</li>
|
||||
<li><b>url</b> - URL of the image,</li>
|
||||
<li><b>thumb_url</b> - URL of a small (thumb) version of the image,</li>
|
||||
<li><b>caption</b> - plain-text string, caption of the image,</li>
|
||||
<li><b>is_spoiler</b> - boolean, if <b>true</b> then the image is
|
||||
a spoiler image and should not be displayed to the user unless
|
||||
the user explicitly asks for it.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>internal_id</b> - undocumented, you <u>should not</u> use
|
||||
this unless you really know you need to. Internal IDs are
|
||||
<b>not</b> unique across various OKAPI installations.
|
||||
Try to use UUIDs instead.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Note, that some fields can change in time (users can edit/delete
|
||||
their log entries).</p>
|
||||
|
||||
<p>If given log entry does not exist, the method will
|
||||
respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -15,58 +15,69 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cache_code = $request->get_parameter('cache_code');
|
||||
if (!$cache_code) throw new ParamMissing('cache_code');
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "uuid|date|user|type|comment";
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cache_code = $request->get_parameter('cache_code');
|
||||
if (!$cache_code) throw new ParamMissing('cache_code');
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "uuid|date|user|type|comment";
|
||||
|
||||
$offset = $request->get_parameter('offset');
|
||||
if (!$offset) $offset = "0";
|
||||
if ((((int)$offset) != $offset) || ((int)$offset) < 0)
|
||||
throw new InvalidParam('offset', "Expecting non-negative integer.");
|
||||
$limit = $request->get_parameter('limit');
|
||||
if (!$limit) $limit = "none";
|
||||
if ($limit == "none") $limit = "999999999";
|
||||
if ((((int)$limit) != $limit) || ((int)$limit) < 0)
|
||||
throw new InvalidParam('limit', "Expecting non-negative integer or 'none'.");
|
||||
$offset = $request->get_parameter('offset');
|
||||
if (!$offset) $offset = "0";
|
||||
if ((((int)$offset) != $offset) || ((int)$offset) < 0)
|
||||
throw new InvalidParam('offset', "Expecting non-negative integer.");
|
||||
$limit = $request->get_parameter('limit');
|
||||
if (!$limit) $limit = "none";
|
||||
if ($limit == "none") $limit = "999999999";
|
||||
if ((((int)$limit) != $limit) || ((int)$limit) < 0)
|
||||
throw new InvalidParam('limit', "Expecting non-negative integer or 'none'.");
|
||||
|
||||
# Check if code exists and retrieve cache ID (this will throw
|
||||
# a proper exception on invalid code).
|
||||
# Check if code exists and retrieve cache ID (this will throw
|
||||
# a proper exception on invalid code).
|
||||
|
||||
$cache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
||||
$cache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
||||
|
||||
# Cache exists. Getting the uuids of its logs.
|
||||
# Cache exists. Getting the uuids of its logs.
|
||||
|
||||
$log_uuids = Db::select_column("
|
||||
select uuid
|
||||
from cache_logs
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($cache['internal_id'])."'
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
order by date desc
|
||||
limit $offset, $limit
|
||||
");
|
||||
$log_uuids = Db::select_column("
|
||||
select uuid
|
||||
from cache_logs
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($cache['internal_id'])."'
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
order by date desc
|
||||
limit $offset, $limit
|
||||
");
|
||||
|
||||
# Getting the logs themselves. Formatting as an ordered list.
|
||||
# Getting the logs themselves. Formatting as an ordered list.
|
||||
|
||||
$internal_request = new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('log_uuids' => implode("|", $log_uuids),
|
||||
'fields' => $fields));
|
||||
$internal_request->skip_limits = true;
|
||||
$logs = OkapiServiceRunner::call('services/logs/entries', $internal_request);
|
||||
$results = array();
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
$results[] = $logs[$log_uuid];
|
||||
$internal_request = new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('log_uuids' => implode("|", $log_uuids),
|
||||
'fields' => $fields));
|
||||
$internal_request->skip_limits = true;
|
||||
$logs = OkapiServiceRunner::call('services/logs/entries', $internal_request);
|
||||
$results = array();
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
$results[] = $logs[$log_uuid];
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
/* Handle OCPL's "access logs" feature. */
|
||||
|
||||
if (
|
||||
(Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
&& Settings::get('OCPL_ENABLE_GEOCACHE_ACCESS_LOGS')
|
||||
&& (count($log_uuids) > 0)
|
||||
) {
|
||||
require_once($GLOBALS['rootpath'].'okapi/lib/ocpl_access_logs.php');
|
||||
\okapi\OCPLAccessLogs::log_geocache_access($request, $cache['internal_id']);
|
||||
}
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
<xml>
|
||||
<brief>Retrieve all log entries for the specified geocache</brief>
|
||||
<issue-id>41</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve the log entries for the specified geocache. Use the offset and
|
||||
limit parameters for pagination. If you want only the latest entries, you
|
||||
may also use the <b>latest_logs</b> field in the services/caches/geocache method.</p>
|
||||
<p>Log entries are ordered by a descending date of the entry.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>
|
||||
<p>Code of the geocache.</p>
|
||||
</req>
|
||||
<opt name='fields' default='uuid|date|user|type|comment'>
|
||||
<p>Same as in the services/logs/entry method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/logs/entry method for a list of available values.</p>
|
||||
</opt>
|
||||
<opt name='offset' default='0'>
|
||||
<p>Number of entries to skip at the beginning. Use this along the <b>limit</b> parameter
|
||||
for pagination.</p>
|
||||
</opt>
|
||||
<opt name='limit' default='none'>
|
||||
<p>Maximum number of entries to return or <b>none</b>
|
||||
if you want all the entries.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A list of log entries, ordered by date. Each log entry is a dictionary of a format
|
||||
described in the "entry" method.</p>
|
||||
</returns>
|
||||
<brief>Retrieve all log entries for the specified geocache</brief>
|
||||
<issue-id>41</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve the log entries for the specified geocache. Use the offset and
|
||||
limit parameters for pagination. If you want only the latest entries, you
|
||||
may also use the <b>latest_logs</b> field in the services/caches/geocache method.</p>
|
||||
<p>Log entries are ordered by a descending date of the entry.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>
|
||||
<p>Code of the geocache.</p>
|
||||
</req>
|
||||
<opt name='fields' default='uuid|date|user|type|comment'>
|
||||
<p>Same as in the services/logs/entry method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/logs/entry method for a list of available values.</p>
|
||||
</opt>
|
||||
<opt name='offset' default='0'>
|
||||
<p>Number of entries to skip at the beginning. Use this along the <b>limit</b> parameter
|
||||
for pagination.</p>
|
||||
</opt>
|
||||
<opt name='limit' default='none'>
|
||||
<p>Maximum number of entries to return or <b>none</b>
|
||||
if you want all the entries.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A list of log entries, ordered by date. Each log entry is a dictionary of a format
|
||||
described in the "entry" method.</p>
|
||||
</returns>
|
||||
</xml>
|
File diff suppressed because it is too large
Load Diff
@ -1,110 +1,110 @@
|
||||
<xml>
|
||||
<brief>Submit a log entry</brief>
|
||||
<issue-id>42</issue-id>
|
||||
<desc>
|
||||
<p>Submit a log entry for the geocache. Please note, that you won't be
|
||||
able to use this method until you learn to handle OAuth.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>
|
||||
<p>Code of the geocache.</p>
|
||||
</req>
|
||||
<req name='logtype'>
|
||||
<p>Type of an entry. This should be one of:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<i>Will attend</i>, <i>Attended</i> or <i>Comment</i> for Event caches;
|
||||
</li>
|
||||
<li>
|
||||
<i>Found it</i>, <i>Didn't find it</i> or <i>Comment</i> for all other
|
||||
cache types.
|
||||
</li>
|
||||
</ul>
|
||||
</req>
|
||||
<opt name='comment'>
|
||||
<p>Text to be submitted with the log entry.</p>
|
||||
</opt>
|
||||
<opt name='comment_format' default='auto'>
|
||||
<p>Indicates the format of your <b>comment</b>. Three values allowed:
|
||||
<b>auto</b>, <b>html</b> or <b>plaintext</b>. Usually, you should <b>not</b>
|
||||
use the <b>auto</b> option, because its exact behavior is unspecified
|
||||
and may depend on the installation
|
||||
(<a href='https://code.google.com/p/opencaching-api/issues/detail?id=124'>more info</a>).</p>
|
||||
<brief>Submit a log entry</brief>
|
||||
<issue-id>42</issue-id>
|
||||
<desc>
|
||||
<p>Submit a log entry for the geocache. Please note, that you won't be
|
||||
able to use this method until you learn to handle OAuth.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>
|
||||
<p>Code of the geocache.</p>
|
||||
</req>
|
||||
<req name='logtype'>
|
||||
<p>Type of an entry. This should be one of:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<i>Will attend</i>, <i>Attended</i> or <i>Comment</i> for Event caches;
|
||||
</li>
|
||||
<li>
|
||||
<i>Found it</i>, <i>Didn't find it</i> or <i>Comment</i> for all other
|
||||
cache types.
|
||||
</li>
|
||||
</ul>
|
||||
</req>
|
||||
<opt name='comment'>
|
||||
<p>Text to be submitted with the log entry.</p>
|
||||
</opt>
|
||||
<opt name='comment_format' default='auto'>
|
||||
<p>Indicates the format of your <b>comment</b>. Three values allowed:
|
||||
<b>auto</b>, <b>html</b> or <b>plaintext</b>. Usually, you should <b>not</b>
|
||||
use the <b>auto</b> option, because its exact behavior is unspecified
|
||||
and may depend on the installation
|
||||
(<a href='https://code.google.com/p/opencaching-api/issues/detail?id=124'>more info</a>).</p>
|
||||
|
||||
<p><b>Important note:</b> The subset of allowed HTML elements is left undefined
|
||||
and may change in the future. For future-compatibility, you should use only
|
||||
basic formatting tags.</p>
|
||||
</opt>
|
||||
<opt name='when'>
|
||||
<p>A date and time string. This should be in ISO 8601 format (currently any
|
||||
format acceptable by PHP's <a href='http://pl2.php.net/strtotime'>strtotime</a>
|
||||
function also will do, but most of them don't handle time zones properly,
|
||||
try to use ISO 8601!).</p>
|
||||
<p>Indicates when the cache was found. If given, the log will be published
|
||||
with the given date and time. If not, log will be published using the current
|
||||
date and time.</p>
|
||||
</opt>
|
||||
<opt name='password'>
|
||||
<p>Some caches require a password in order to submit a "Found it" log entry.
|
||||
You may check if this cache requires password with <b>req_passwd</b> field
|
||||
of the services/caches/geocache method.</p>
|
||||
</opt>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for error messages.</p>
|
||||
</opt>
|
||||
<opt name='on_duplicate' default='silent_success'>
|
||||
<p>How should OKAPI react when you are trying to submit a duplicate entry?
|
||||
One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>silent_success</b> - try to respond with success=true, but don't
|
||||
add a new log entry (existing log_uuid will be returned),</li>
|
||||
<li><b>user_error</b> - respond with success=false and a proper user message,</li>
|
||||
<li><b>continue</b> - don't detect duplicates (note, that this will still
|
||||
fail in some cases, i.e. when you're trying to submit a "Found it" entry for an
|
||||
already found cache).</li>
|
||||
</ul>
|
||||
<p>Note, that duplicate detection may take the <b>when</b> parameter into account.
|
||||
When you don't supply it, "when" is generated for you. This means that you may
|
||||
have to supply the "when" parameter if you want duplicate detection to work.</p>
|
||||
</opt>
|
||||
<opt name='rating'>
|
||||
<p>An integer in range between 1 and 5 - user's optional rating of a found cache.</p>
|
||||
<p>Important: <b>logtype</b> has to be "Found it" in order to use this argument.</p>
|
||||
<p>Note: You should allow your user to <b>not</b> rate a found cache.</p>
|
||||
<p>Note: Currently, some OC installations do not support cache ratings. On such installations
|
||||
user's rating will be <b>ignored</b> (if you include the rating, log entry will be posted
|
||||
successfully, but rating will be ignored).</p>
|
||||
</opt>
|
||||
<opt name='recommend' default='false'>
|
||||
<p>Set to <b>true</b> if the user wants to recommend this cache.</p>
|
||||
<p>Important: <b>logtype</b> has to be "Found it" or "Attended" in order to
|
||||
use this argument. However, some installations do not support recommending
|
||||
event caches (if you include a recommendation, the log entry will be posted
|
||||
successfully, but the recommendation will be <b>ignored</b>).</p>
|
||||
<p>Recommending may only succeed when the user meets certain criteria
|
||||
set on him by the OC site. If criteria are not met, the request will
|
||||
end with user error (HTTP 200, success=false).</p>
|
||||
</opt>
|
||||
<opt name='needs_maintenance' default='false'>
|
||||
<p>Set to <b>true</b> if the user thinks that the cache needs some special attension
|
||||
of its owner. Users should describe the reason for maintenance in their comments.</p>
|
||||
<p>Note: Depending on OC installation and user's log entry type, OKAPI may actually
|
||||
publish two separate log entries when you check this flag (one of them with empty
|
||||
comment). Even then, you will still receive only one UUID reference (pointing to
|
||||
only one of those entries). Moreover, on some OC servers this flag might be
|
||||
<b>completely ignored</b> (not all OC servers support this feature).</p>
|
||||
<p>Note: Currently, this is not allowed for Event Caches (you will get a HTTP 200
|
||||
"user friendly" response).</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>success</b> - true, if the log entry was submitted successfully,</li>
|
||||
<li><b>message</b> - plain-text string, a message for the user, which acknowledges success
|
||||
or describes an error (usually you want to display this only when success is false),</li>
|
||||
<li><b>log_uuid</b> - ID of the newly created log entry, <b>or null</b>
|
||||
in case of an error.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<p><b>Important note:</b> The subset of allowed HTML elements is left undefined
|
||||
and may change in the future. For future-compatibility, you should use only
|
||||
basic formatting tags.</p>
|
||||
</opt>
|
||||
<opt name='when'>
|
||||
<p>A date and time string. This should be in ISO 8601 format (currently any
|
||||
format acceptable by PHP's <a href='http://pl2.php.net/strtotime'>strtotime</a>
|
||||
function also will do, but most of them don't handle time zones properly,
|
||||
try to use ISO 8601!).</p>
|
||||
<p>Indicates when the cache was found. If given, the log will be published
|
||||
with the given date and time. If not, log will be published using the current
|
||||
date and time.</p>
|
||||
</opt>
|
||||
<opt name='password'>
|
||||
<p>Some caches require a password in order to submit a "Found it" log entry.
|
||||
You may check if this cache requires password with <b>req_passwd</b> field
|
||||
of the services/caches/geocache method.</p>
|
||||
</opt>
|
||||
<opt name='langpref' default='en'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for error messages.</p>
|
||||
</opt>
|
||||
<opt name='on_duplicate' default='silent_success'>
|
||||
<p>How should OKAPI react when you are trying to submit a duplicate entry?
|
||||
One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>silent_success</b> - try to respond with success=true, but don't
|
||||
add a new log entry (existing log_uuid will be returned),</li>
|
||||
<li><b>user_error</b> - respond with success=false and a proper user message,</li>
|
||||
<li><b>continue</b> - don't detect duplicates (note, that this will still
|
||||
fail in some cases, i.e. when you're trying to submit a "Found it" entry for an
|
||||
already found cache).</li>
|
||||
</ul>
|
||||
<p>Note, that duplicate detection may take the <b>when</b> parameter into account.
|
||||
When you don't supply it, "when" is generated for you. This means that you may
|
||||
have to supply the "when" parameter if you want duplicate detection to work.</p>
|
||||
</opt>
|
||||
<opt name='rating'>
|
||||
<p>An integer in range between 1 and 5 - user's optional rating of a found cache.</p>
|
||||
<p>Important: <b>logtype</b> has to be "Found it" in order to use this argument.</p>
|
||||
<p>Note: You should allow your user to <b>not</b> rate a found cache.</p>
|
||||
<p>Note: Currently, some OC installations do not support cache ratings. On such installations
|
||||
user's rating will be <b>ignored</b> (if you include the rating, log entry will be posted
|
||||
successfully, but rating will be ignored).</p>
|
||||
</opt>
|
||||
<opt name='recommend' default='false'>
|
||||
<p>Set to <b>true</b> if the user wants to recommend this cache.</p>
|
||||
<p>Important: <b>logtype</b> has to be "Found it" or "Attended" in order to
|
||||
use this argument. However, some installations do not support recommending
|
||||
event caches (if you include a recommendation, the log entry will be posted
|
||||
successfully, but the recommendation will be <b>ignored</b>).</p>
|
||||
<p>Recommending may only succeed when the user meets certain criteria
|
||||
set on him by the OC site. If criteria are not met, the request will
|
||||
end with user error (HTTP 200, success=false).</p>
|
||||
</opt>
|
||||
<opt name='needs_maintenance' default='false'>
|
||||
<p>Set to <b>true</b> if the user thinks that the cache needs some special attension
|
||||
of its owner. Users should describe the reason for maintenance in their comments.</p>
|
||||
<p>Note: Depending on OC installation and user's log entry type, OKAPI may actually
|
||||
publish two separate log entries when you check this flag (one of them with empty
|
||||
comment). Even then, you will still receive only one UUID reference (pointing to
|
||||
only one of those entries). Moreover, on some OC servers this flag might be
|
||||
<b>completely ignored</b> (not all OC servers support this feature).</p>
|
||||
<p>Note: Currently, this is not allowed for Event Caches (you will get a HTTP 200
|
||||
"user friendly" response).</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>success</b> - true, if the log entry was submitted successfully,</li>
|
||||
<li><b>message</b> - plain-text string, a message for the user, which acknowledges success
|
||||
or describes an error (usually you want to display this only when success is false),</li>
|
||||
<li><b>log_uuid</b> - ID of the newly created log entry, <b>or null</b>
|
||||
in case of an error.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -15,62 +15,62 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
if (!$user_uuid) throw new ParamMissing('user_uuid');
|
||||
$limit = $request->get_parameter('limit');
|
||||
if (!$limit) $limit = "20";
|
||||
if (!is_numeric($limit))
|
||||
throw new InvalidParam('limit', "'$limit'");
|
||||
$limit = intval($limit);
|
||||
if (($limit < 1) || ($limit > 1000))
|
||||
throw new InvalidParam('limit', "Has to be in range 1..1000.");
|
||||
$offset = $request->get_parameter('offset');
|
||||
if (!$offset) $offset = "0";
|
||||
if (!is_numeric($offset))
|
||||
throw new InvalidParam('offset', "'$offset'");
|
||||
$offset = intval($offset);
|
||||
if ($offset < 0)
|
||||
throw new InvalidParam('offset', "'$offset'");
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
if (!$user_uuid) throw new ParamMissing('user_uuid');
|
||||
$limit = $request->get_parameter('limit');
|
||||
if (!$limit) $limit = "20";
|
||||
if (!is_numeric($limit))
|
||||
throw new InvalidParam('limit', "'$limit'");
|
||||
$limit = intval($limit);
|
||||
if (($limit < 1) || ($limit > 1000))
|
||||
throw new InvalidParam('limit', "Has to be in range 1..1000.");
|
||||
$offset = $request->get_parameter('offset');
|
||||
if (!$offset) $offset = "0";
|
||||
if (!is_numeric($offset))
|
||||
throw new InvalidParam('offset', "'$offset'");
|
||||
$offset = intval($offset);
|
||||
if ($offset < 0)
|
||||
throw new InvalidParam('offset', "'$offset'");
|
||||
|
||||
# Check if user exists and retrieve user's ID (this will throw
|
||||
# a proper exception on invalid UUID).
|
||||
$user = OkapiServiceRunner::call('services/users/user', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('user_uuid' => $user_uuid, 'fields' => 'internal_id')));
|
||||
# Check if user exists and retrieve user's ID (this will throw
|
||||
# a proper exception on invalid UUID).
|
||||
$user = OkapiServiceRunner::call('services/users/user', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('user_uuid' => $user_uuid, 'fields' => 'internal_id')));
|
||||
|
||||
# User exists. Retrieving logs.
|
||||
# User exists. Retrieving logs.
|
||||
|
||||
$rs = Db::query("
|
||||
select cl.id, cl.uuid, cl.type, unix_timestamp(cl.date) as date, cl.text,
|
||||
c.wp_oc as cache_code
|
||||
from cache_logs cl, caches c
|
||||
where
|
||||
cl.user_id = '".mysql_real_escape_string($user['internal_id'])."'
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
||||
and c.status in (1,2,3)
|
||||
and cl.cache_id = c.cache_id
|
||||
order by cl.date desc
|
||||
limit $offset, $limit
|
||||
");
|
||||
$results = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$results[] = array(
|
||||
'uuid' => $row['uuid'],
|
||||
'date' => date('c', $row['date']),
|
||||
'cache_code' => $row['cache_code'],
|
||||
'type' => Okapi::logtypeid2name($row['type']),
|
||||
'comment' => $row['text']
|
||||
);
|
||||
}
|
||||
$rs = Db::query("
|
||||
select cl.id, cl.uuid, cl.type, unix_timestamp(cl.date) as date, cl.text,
|
||||
c.wp_oc as cache_code
|
||||
from cache_logs cl, caches c
|
||||
where
|
||||
cl.user_id = '".mysql_real_escape_string($user['internal_id'])."'
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
||||
and c.status in (1,2,3)
|
||||
and cl.cache_id = c.cache_id
|
||||
order by cl.date desc
|
||||
limit $offset, $limit
|
||||
");
|
||||
$results = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$results[] = array(
|
||||
'uuid' => $row['uuid'],
|
||||
'date' => date('c', $row['date']),
|
||||
'cache_code' => $row['cache_code'],
|
||||
'type' => Okapi::logtypeid2name($row['type']),
|
||||
'comment' => $row['text']
|
||||
);
|
||||
}
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -1,41 +1,45 @@
|
||||
<xml>
|
||||
<brief>Retrieve log entries of a specified user</brief>
|
||||
<issue-id>80</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve log entries of a specified user.</p>
|
||||
</desc>
|
||||
<req name='user_uuid'>
|
||||
<p>ID of the user. (Use services/users/by_username to get it.)</p>
|
||||
</req>
|
||||
<opt name='limit' default='20'>
|
||||
<p>Integer N. If given, no more than N logs will be returned (the most recent ones).
|
||||
Maximum allowed value is 1000.</p>
|
||||
<p>Note: Some users have thousands of log entries!</p>
|
||||
</opt>
|
||||
<opt name='offset' default='0'>
|
||||
<p>Combined with the <b>limit</b> argument, this gives you an abbility to get
|
||||
<b>all</b> log entries of the user (with multiple requests).</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>Log entries. A dictionary of the following format:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - ID of the log entry,</li>
|
||||
<li>
|
||||
<p><b>date</b> - date and time (ISO 8601) when the log entry was submitted.</p>
|
||||
<p>Please note that log entries often contain dates only (with the times
|
||||
truncated to midnight, as in the local timezone). In such cases, you may
|
||||
want to avoid displaying the time. You may assume that if the <b>date</b>
|
||||
value contains the "00:00:00" string, then it is date-only.</p>
|
||||
</li>
|
||||
<li><b>cache_code</b> - code of the geocache,</li>
|
||||
<li>
|
||||
<p><b>type</b> - string; log type. This could be <b>pretty much
|
||||
everything</b>, but there are some primary types (see logs/entry
|
||||
method for more info).</p>
|
||||
</li>
|
||||
<li><b>comment</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>, text entered
|
||||
with the log entry.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Retrieve log entries of a specified user</brief>
|
||||
<issue-id>80</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve log entries of a specified user.</p>
|
||||
</desc>
|
||||
<req name='user_uuid'>
|
||||
<p>ID of the user. (Use services/users/by_username to get it.)</p>
|
||||
</req>
|
||||
<opt name='limit' default='20'>
|
||||
<p>Integer N. If given, no more than N logs will be returned (the most recent ones).
|
||||
Maximum allowed value is 1000.</p>
|
||||
<p>Note: Some users have thousands of log entries!</p>
|
||||
</opt>
|
||||
<opt name='offset' default='0'>
|
||||
<p>Combined with the <b>limit</b> argument, this gives you an abbility to get
|
||||
<b>all</b> log entries of the user (with multiple requests).</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A list of log entries, ordered by descending date. Each entry is a
|
||||
dictionary of the following format:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>uuid</b> - ID of the log entry,</li>
|
||||
<li>
|
||||
<p><b>date</b> - date and time (ISO 8601) when the log entry was submitted.</p>
|
||||
<p>Please note that log entries often contain dates only (with the times
|
||||
truncated to midnight, as in the local timezone). In such cases, you may
|
||||
want to avoid displaying the time. You may assume that if the <b>date</b>
|
||||
value contains the "00:00:00" string, then it is date-only.</p>
|
||||
</li>
|
||||
<li><b>cache_code</b> - code of the geocache,</li>
|
||||
<li>
|
||||
<p><b>type</b> - string; log type. This could be <b>pretty much
|
||||
everything</b>, but there are some primary types (see logs/entry
|
||||
method for more info).</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>comment</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>, text entered
|
||||
with the log entry.
|
||||
</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@ -10,28 +10,28 @@ use okapi\InvalidParam;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 3,
|
||||
'token_type' => 'request'
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 3,
|
||||
'token_type' => 'request'
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$verifier = $request->get_parameter('oauth_verifier');
|
||||
if (!$verifier)
|
||||
{
|
||||
# We require the 1.0a flow (throw an error when there is no oauth_verifier).
|
||||
throw new ParamMissing("oauth_verifier");
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$verifier = $request->get_parameter('oauth_verifier');
|
||||
if (!$verifier)
|
||||
{
|
||||
# We require the 1.0a flow (throw an error when there is no oauth_verifier).
|
||||
throw new ParamMissing("oauth_verifier");
|
||||
}
|
||||
|
||||
$new_token = Okapi::$data_store->new_access_token($request->token, $request->consumer, $verifier);
|
||||
$new_token = Okapi::$data_store->new_access_token($request->token, $request->consumer, $verifier);
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
$response->body = $new_token;
|
||||
return $response;
|
||||
}
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
$response->body = $new_token;
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
<xml>
|
||||
<brief>Exchange authorized Request Token for an Access Token</brief>
|
||||
<issue-id>21</issue-id>
|
||||
<desc>
|
||||
<p>Exchange authorized Request Token for an Access Token.
|
||||
Access Token can be used to access resources of a user who
|
||||
authorized the Request Token.</p>
|
||||
<p>Standard OAuth "Consumer & Request Token" Authorization arguments
|
||||
are required.</p>
|
||||
</desc>
|
||||
<req name='oauth_verifier'>
|
||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||
</req>
|
||||
<returns>
|
||||
<p>Standard OAuth 1.0a Token response - a string in a form-encoded format:</p>
|
||||
<pre>oauth_token=...&oauth_token_secret=...</pre>
|
||||
<p>You <b>must</b> be prepared that there might be more parameters returned
|
||||
in the future (you should ignore them gracefully).</p>
|
||||
</returns>
|
||||
<brief>Exchange authorized Request Token for an Access Token</brief>
|
||||
<issue-id>21</issue-id>
|
||||
<desc>
|
||||
<p>Exchange authorized Request Token for an Access Token.
|
||||
Access Token can be used to access resources of a user who
|
||||
authorized the Request Token.</p>
|
||||
<p>Standard OAuth "Consumer & Request Token" Authorization arguments
|
||||
are required.</p>
|
||||
</desc>
|
||||
<req name='oauth_verifier'>
|
||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||
</req>
|
||||
<returns>
|
||||
<p>Standard OAuth 1.0a Token response - a string in a form-encoded format:</p>
|
||||
<pre>oauth_token=...&oauth_token_secret=...</pre>
|
||||
<p>You <b>must</b> be prepared that there might be more parameters returned
|
||||
in the future (you should ignore them gracefully).</p>
|
||||
</returns>
|
||||
</xml>
|
||||
|
@ -11,31 +11,31 @@ use okapi\InvalidParam;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$token_key = $request->get_parameter('oauth_token');
|
||||
if (!$token_key)
|
||||
throw new ParamMissing("oauth_token");
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
$interactivity = $request->get_parameter('interactivity');
|
||||
if (!$interactivity) $interactivity = 'minimal';
|
||||
if (!in_array($interactivity, array('minimal', 'confirm_user')))
|
||||
throw new InvalidParam('interactivity', $interactivity);
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$token_key = $request->get_parameter('oauth_token');
|
||||
if (!$token_key)
|
||||
throw new ParamMissing("oauth_token");
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
$interactivity = $request->get_parameter('interactivity');
|
||||
if (!$interactivity) $interactivity = 'minimal';
|
||||
if (!in_array($interactivity, array('minimal', 'confirm_user')))
|
||||
throw new InvalidParam('interactivity', $interactivity);
|
||||
|
||||
# Redirect to the "apps" folder. This is done there (not here)
|
||||
# because: 1) we don't want any cookie or session-handling
|
||||
# done in the "services" folder. 2) "services" don't display
|
||||
# any interactive webpages, they just return the result.
|
||||
# Redirect to the "apps" folder. This is done there (not here)
|
||||
# because: 1) we don't want any cookie or session-handling
|
||||
# done in the "services" folder. 2) "services" don't display
|
||||
# any interactive webpages, they just return the result.
|
||||
|
||||
return new OkapiRedirectResponse(Settings::get('SITE_URL')."okapi/apps/authorize".
|
||||
"?oauth_token=".$token_key.(($langpref != null) ? "&langpref=".$langpref : "").
|
||||
"&interactivity=".$interactivity);
|
||||
}
|
||||
return new OkapiRedirectResponse(Settings::get('SITE_URL')."okapi/apps/authorize".
|
||||
"?oauth_token=".$token_key.(($langpref != null) ? "&langpref=".$langpref : "").
|
||||
"&interactivity=".$interactivity);
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +1,66 @@
|
||||
<xml>
|
||||
<brief>Authorize the Request Token</brief>
|
||||
<issue-id>22</issue-id>
|
||||
<desc>
|
||||
<p>Unlike other methods, the <b>authorize</b> method is to be executed
|
||||
inside the User's browser. Consumer's role is to <b>redirect</b> the User to
|
||||
this URL, then wait if he ever comes back with a callback request.</p>
|
||||
<p>Once the User is redirected to this URL, several things will happen:</p>
|
||||
<ul>
|
||||
<li>If he's not already logged in, he will be asked to do so.</li>
|
||||
<li>OKAPI will check if the User haven't previously granted your
|
||||
application access to his Opencaching account.</li>
|
||||
<li>If User did not previously authorize your application, OKAPI
|
||||
will display an "Authorization Request" form to the User. User
|
||||
will be presented with a choice to allow or not to allow your
|
||||
application access to his account.</li>
|
||||
<li>If the User clicks one of these two options ("allow" or "don't allow"),
|
||||
he's browser will be redirected to the <b>callback_url</b> you defined
|
||||
while getting your Request Token.
|
||||
If you did not provide a callback (in other word, provided "oob"),
|
||||
user will be redirected to a default "authorized" page, where he
|
||||
will be presented with an oauth_verifier (user will know it
|
||||
by name of a <b>PIN code</b>) and asked to type it into your application.</li>
|
||||
</ul>
|
||||
</desc>
|
||||
<req name='oauth_token'>
|
||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||
</req>
|
||||
<opt name='interactivity' default='minimal'>
|
||||
<p>Currently, one of the following values:</p>
|
||||
<ul>
|
||||
<li><b>minimal</b> - OKAPI will use as little interactivity as it can.
|
||||
It will assume that currently logged in user is the user which you
|
||||
want to authorize. If the user has already authorized your application,
|
||||
he will not be asked to do this again.</li>
|
||||
<li><b>confirm_user</b> - even if a user is logged in, OKAPI will NOT
|
||||
assume that this is the user who wants to be authorized. OKAPI will
|
||||
offer to authorize a different user (e.g. by automatically logging out
|
||||
the user who is currently logged in).</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name='langpref'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which the language will be chosen for the authorization page.</p>
|
||||
<p>By default, OKAPI will display the page in the primary native language of local
|
||||
Opencaching installation.</p>
|
||||
</opt>
|
||||
<returns>
|
||||
<p>Technically, an HTTP 302 Redirect - it will direct user's browser to the OKAPI apps
|
||||
authorization page.</p>
|
||||
<p>Whether with callback_url or with a manual user entry - you will get
|
||||
your <b>oauth_verifier</b>, which allows you to continue the 3-legged
|
||||
authentication dance.</p>
|
||||
<p>If you used <b>callback_url</b>, you should wait for an HTTP GET request,
|
||||
with one additional GET parameter appended:</p>
|
||||
<ul>
|
||||
<li><b>oauth_token</b> - the Request Token that has been just authorized,</li>
|
||||
<li><b>oauth_verifier</b> - the PIN code required to get an Access Token.</li>
|
||||
</ul>
|
||||
<p>OR, in case when user denied the request:</p>
|
||||
<ul>
|
||||
<li><b>oauth_token</b> - the Request Token,</li>
|
||||
<li><b>error</b> - codename of an error - <b>access_denied</b>.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Authorize the Request Token</brief>
|
||||
<issue-id>22</issue-id>
|
||||
<desc>
|
||||
<p>Unlike other methods, the <b>authorize</b> method is to be executed
|
||||
inside the User's browser. Consumer's role is to <b>redirect</b> the User to
|
||||
this URL, then wait if he ever comes back with a callback request.</p>
|
||||
<p>Once the User is redirected to this URL, several things will happen:</p>
|
||||
<ul>
|
||||
<li>If he's not already logged in, he will be asked to do so.</li>
|
||||
<li>OKAPI will check if the User haven't previously granted your
|
||||
application access to his Opencaching account.</li>
|
||||
<li>If User did not previously authorize your application, OKAPI
|
||||
will display an "Authorization Request" form to the User. User
|
||||
will be presented with a choice to allow or not to allow your
|
||||
application access to his account.</li>
|
||||
<li>If the User clicks one of these two options ("allow" or "don't allow"),
|
||||
he's browser will be redirected to the <b>callback_url</b> you defined
|
||||
while getting your Request Token.
|
||||
If you did not provide a callback (in other word, provided "oob"),
|
||||
user will be redirected to a default "authorized" page, where he
|
||||
will be presented with an oauth_verifier (user will know it
|
||||
by name of a <b>PIN code</b>) and asked to type it into your application.</li>
|
||||
</ul>
|
||||
</desc>
|
||||
<req name='oauth_token'>
|
||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||
</req>
|
||||
<opt name='interactivity' default='minimal'>
|
||||
<p>Currently, one of the following values:</p>
|
||||
<ul>
|
||||
<li><b>minimal</b> - OKAPI will use as little interactivity as it can.
|
||||
It will assume that currently logged in user is the user which you
|
||||
want to authorize. If the user has already authorized your application,
|
||||
he will not be asked to do this again.</li>
|
||||
<li><b>confirm_user</b> - even if a user is logged in, OKAPI will NOT
|
||||
assume that this is the user who wants to be authorized. OKAPI will
|
||||
offer to authorize a different user (e.g. by automatically logging out
|
||||
the user who is currently logged in).</li>
|
||||
</ul>
|
||||
</opt>
|
||||
<opt name='langpref'>
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which the language will be chosen for the authorization page.</p>
|
||||
<p>By default, OKAPI will display the page in the primary native language of local
|
||||
Opencaching installation.</p>
|
||||
</opt>
|
||||
<returns>
|
||||
<p>Technically, an HTTP 302 Redirect - it will direct user's browser to the OKAPI apps
|
||||
authorization page.</p>
|
||||
<p>Whether with callback_url or with a manual user entry - you will get
|
||||
your <b>oauth_verifier</b>, which allows you to continue the 3-legged
|
||||
authentication dance.</p>
|
||||
<p>If you used <b>callback_url</b>, you should wait for an HTTP GET request,
|
||||
with one additional GET parameter appended:</p>
|
||||
<ul>
|
||||
<li><b>oauth_token</b> - the Request Token that has been just authorized,</li>
|
||||
<li><b>oauth_verifier</b> - the PIN code required to get an Access Token.</li>
|
||||
</ul>
|
||||
<p>OR, in case when user denied the request:</p>
|
||||
<ul>
|
||||
<li><b>oauth_token</b> - the Request Token,</li>
|
||||
<li><b>error</b> - codename of an error - <b>access_denied</b>.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
||||
|
@ -10,27 +10,27 @@ use okapi\InvalidParam;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 2
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 2
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$callback = $request->get_parameter('oauth_callback');
|
||||
if (!$callback)
|
||||
{
|
||||
# We require the 1.0a flow (throw an error when there is no oauth_callback).
|
||||
throw new ParamMissing("oauth_callback");
|
||||
}
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$callback = $request->get_parameter('oauth_callback');
|
||||
if (!$callback)
|
||||
{
|
||||
# We require the 1.0a flow (throw an error when there is no oauth_callback).
|
||||
throw new ParamMissing("oauth_callback");
|
||||
}
|
||||
|
||||
$new_token = Okapi::$data_store->new_request_token($request->consumer, $callback);
|
||||
$new_token = Okapi::$data_store->new_request_token($request->consumer, $callback);
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
$response->body = $new_token."&oauth_callback_confirmed=true";
|
||||
return $response;
|
||||
}
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
$response->body = $new_token."&oauth_callback_confirmed=true";
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
<xml>
|
||||
<brief>Get a new unauthorized OAuth Request Token</brief>
|
||||
<issue-id>23</issue-id>
|
||||
<desc>
|
||||
<p>Get a new unauthorized OAuth Request Token. This token is bound to
|
||||
the Consumer it was issued to. It has a short expiration date and
|
||||
can be used in one way only - first it has to get authorized by
|
||||
the user, then it has to be exchanged for an Access Token.</p>
|
||||
</desc>
|
||||
<req name='oauth_callback'>
|
||||
<p>URL which you want a User to be redirected to after a
|
||||
successful Request Token Authorization (see "authorize" method).
|
||||
If the client is unable to receive callbacks, the parameter
|
||||
must be set to "oob", OKAPI will provide a user with a
|
||||
PIN code (oauth_verifier) in this case.</p>
|
||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||
</req>
|
||||
<returns>
|
||||
<p>Standard OAuth 1.0a Token response - a string in a form-encoded format:</p>
|
||||
<pre>oauth_token=...&oauth_token_secret=...&oauth_callback_confirmed=true</pre>
|
||||
<p>You <b>must</b> be prepared that there might be more parameters returned
|
||||
in the future (you should ignore them gracefully).</p>
|
||||
</returns>
|
||||
<brief>Get a new unauthorized OAuth Request Token</brief>
|
||||
<issue-id>23</issue-id>
|
||||
<desc>
|
||||
<p>Get a new unauthorized OAuth Request Token. This token is bound to
|
||||
the Consumer it was issued to. It has a short expiration date and
|
||||
can be used in one way only - first it has to get authorized by
|
||||
the user, then it has to be exchanged for an Access Token.</p>
|
||||
</desc>
|
||||
<req name='oauth_callback'>
|
||||
<p>URL which you want a User to be redirected to after a
|
||||
successful Request Token Authorization (see "authorize" method).
|
||||
If the client is unable to receive callbacks, the parameter
|
||||
must be set to "oob", OKAPI will provide a user with a
|
||||
PIN code (oauth_verifier) in this case.</p>
|
||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||
</req>
|
||||
<returns>
|
||||
<p>Standard OAuth 1.0a Token response - a string in a form-encoded format:</p>
|
||||
<pre>oauth_token=...&oauth_token_secret=...&oauth_callback_confirmed=true</pre>
|
||||
<p>You <b>must</b> be prepared that there might be more parameters returned
|
||||
in the future (you should ignore them gracefully).</p>
|
||||
</returns>
|
||||
</xml>
|
||||
|
@ -17,37 +17,37 @@ use okapi\services\replicate\ReplicateCommon;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
|
||||
$since = $request->get_parameter('since');
|
||||
if ($since === null) throw new ParamMissing('since');
|
||||
if ((int)$since != $since) throw new InvalidParam('since');
|
||||
$since = $request->get_parameter('since');
|
||||
if ($since === null) throw new ParamMissing('since');
|
||||
if ((int)$since != $since) throw new InvalidParam('since');
|
||||
|
||||
# Let's check the $since parameter.
|
||||
# Let's check the $since parameter.
|
||||
|
||||
if (!ReplicateCommon::check_since_param($since))
|
||||
throw new BadRequest("The 'since' parameter is too old. You must update your database more frequently.");
|
||||
if (!ReplicateCommon::check_since_param($since))
|
||||
throw new BadRequest("The 'since' parameter is too old. You must update your database more frequently.");
|
||||
|
||||
# Select a best chunk for the given $since, get the chunk from the database (or cache).
|
||||
# Select a best chunk for the given $since, get the chunk from the database (or cache).
|
||||
|
||||
list($from, $to) = ReplicateCommon::select_best_chunk($since);
|
||||
$clog_entries = ReplicateCommon::get_chunk($from, $to);
|
||||
list($from, $to) = ReplicateCommon::select_best_chunk($since);
|
||||
$clog_entries = ReplicateCommon::get_chunk($from, $to);
|
||||
|
||||
$result = array(
|
||||
'changelog' => &$clog_entries,
|
||||
'revision' => $to + 0,
|
||||
'more' => $to < ReplicateCommon::get_revision(),
|
||||
);
|
||||
$result = array(
|
||||
'changelog' => &$clog_entries,
|
||||
'revision' => $to + 0,
|
||||
'more' => $to < ReplicateCommon::get_revision(),
|
||||
);
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,133 +1,140 @@
|
||||
<xml>
|
||||
<brief>Get the list of changes for your database</brief>
|
||||
<issue-id>109</issue-id>
|
||||
<desc>
|
||||
<p><b>Beta status.</b> Get the list of changes to be replayed on your own copy
|
||||
of Opencaching database. Use this method periodically (ex. once per hour) to
|
||||
keep your database in sync with ours.</p>
|
||||
|
||||
<p>For some applications it might be desireable to have a quick access to the entire
|
||||
Opencaching database (instead of querying for specific portions of it). You may use
|
||||
OKAPI's <b>replicate</b> module to achive this effect. The <b>changelog</b> method
|
||||
is the primary replication service which you will use. However, to correctly set up
|
||||
your first database copy, you will need to use the <b>fulldump</b> method.</p>
|
||||
|
||||
<p>A couple of things for you to remember:</p>
|
||||
<ul>
|
||||
<li>You <b>must</b> update your database frequently for this method to work.
|
||||
We don't keep the changelog indefinitelly. You must update at least once every week.</li>
|
||||
<li>You <b>should not</b> update your database more frequently than once every
|
||||
5 minutes. This won't do you any good, since we update the changelog only once
|
||||
every 5 minutes anyway.</li>
|
||||
</ul>
|
||||
|
||||
<p>Let's assume that you already have a copy of OKAPI database, but it's
|
||||
already 2 days old. You want to use the <b>changelog</b> method to update
|
||||
your copy to the most current state.</p>
|
||||
|
||||
<p>Changelog is the list of all changes which appeared in the OKAPI database
|
||||
since the last time you downloaded it. What you have to do is to download this
|
||||
list of changes and to replay them on your copy of our database. After you do
|
||||
this, your database is up-to-date.</p>
|
||||
|
||||
<p>We use <b>revision</b> numbers to keep track of all the versions of the
|
||||
database. Every time you update a database, you receive the <b>revision</b>
|
||||
number along with it. You must keep this number carefully, because you need
|
||||
it in order for us to generate a proper changelog for you next time you ask
|
||||
for it.</p>
|
||||
|
||||
<p>Example. This is a valid list of requests you should issue and their
|
||||
responses:</p>
|
||||
<ul>
|
||||
<li><b>fulldump</b> - you receive a fulldump of our database with the
|
||||
revision number 238004. <b>You will call this method only once, never again.</b></li>
|
||||
<li><b>changelog</b>?since=238004 - OKAPI checks if there were any changes
|
||||
recorded since revision 238004. It responds with the list of changes and the
|
||||
new revision number 238017. You replay the changes on your database.</li>
|
||||
<li>You wait for some time between requesting the changelog again.</li>
|
||||
<li><b>changelog</b>?since=238017 - etc.</li>
|
||||
</ul>
|
||||
</desc>
|
||||
<req name='since'>
|
||||
<p>Current revision of your database. This should be the same as the value
|
||||
of <b>revision</b> attribute, which you received with your previous update.</p>
|
||||
|
||||
<p>Old revisions are deleted, the <b>since</b> argument MUST referer to a revision no older
|
||||
than 10 days. You will have to download a fulldump if you have an older copy
|
||||
(shame on you!).</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><b>changelog</b> - a <b>list</b> of dictionaries. Each dictionary has the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><b>object_type</b> - string, object type to which the change refers to. One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>geocache</b> - this change refers to a geocache object,</li>
|
||||
<li><b>log_entry</b> - this change refers to a log entry.</li>
|
||||
</ul>
|
||||
<p>More object types will come in the future. You should ignore all changelog
|
||||
entries with an unknown object_type.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>object_key</b> - a dictionary of fields which compose the primary key for the object.
|
||||
This will be the <b>code</b> field for the <b>geocache</b> object, and <b>uuid</b> field
|
||||
for the <b>log_entry</b> object.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>change_type</b> - string, the type of the change. One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>replace</b> - the object was inserted or updated. You should check if you
|
||||
already have the object in your database. If you have it, you should update its
|
||||
fields accordingly. If you don't, you should create it.</li>
|
||||
<li><b>delete</b> - the object was deleted. You should check if you already have
|
||||
the object in your database. If you do, you should delete it.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>fields</b> - a dictionary of fields associated with the object (present only
|
||||
if <b>change_type</b> equals <b>replace</b>).</p>
|
||||
<ul>
|
||||
<li>For <b>geocache</b> objects, this might be any subset of fields described
|
||||
in the services/caches/geocache method. Note that not all of these fields will
|
||||
be included here (i.e. latest_logs will not).</li>
|
||||
<li>For <b>log_entry</b> objects, this might be any subset of fields described
|
||||
in the services/logs/logs method, <b>plus</b> additional <b>cache_code</b> field,
|
||||
the code of the geocache to which the log entry refers to.</li>
|
||||
</ul>
|
||||
<p>In theory this dictionary should contain only these fields which actually changed.
|
||||
In truth, it MAY contain all the other fields too. This behavior may change in future.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>You should iterate through this changelog sequentially. All the changes should be applied
|
||||
in the same order as they were listed in the changelog. Single object may appear multiple times
|
||||
inside the changelog. Changelog will contain all the changes which occured since the time you
|
||||
specified in the <b>since</b> parameter and it MAY contain some more, which were submitted
|
||||
<b>before</b> this date (see below). The changes which are unnecessary MAY be skipped (ex. when
|
||||
cache description changes multiple times, we may want to include only the last change).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>revision</b> - this is the revision number which you should use in the <b>since</b> parameter
|
||||
when you call this method next time.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>more</b> - boolean. If <b>false</b>, then it means that the entire changelog had been
|
||||
pulled. If <b>true</b>, then there are more items waiting to be pulled - you should rerun this
|
||||
method again (with the value of <b>revision</b> inserted in the <b>since</b> parameter).</p>
|
||||
<p>The changelog is usually tiny, but it also might be huge at times. It may even
|
||||
contain all the caches in the database (i.e. if we decide to do some changes on all
|
||||
caches in a bulk). This is the reason why we introduced the <b>more</b> attribute. It makes it
|
||||
easier to parse the changelog sequentially.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>The response MAY contain changes recorded before the revision which you stated in your <b>since</b>
|
||||
parameter. This is due to caching. If we already have a response ready, that was produced for a
|
||||
"since" parameter which was a little more in the past, we may want to return this cached copy,
|
||||
instead of producing a new one. It will be faster for us, and you shouldn't even notice. We will
|
||||
still make sure to set the <b>revision</b> and <b>more</b> attributes in a correct way, which
|
||||
in turn will make you query us again, if you need to.</p>
|
||||
</returns>
|
||||
<brief>Get the list of changes for your database</brief>
|
||||
<issue-id>109</issue-id>
|
||||
<desc>
|
||||
<p>Get the list of changes to be <u>replayed on your own copy
|
||||
of Opencaching database</u>. Use this method periodically (e.g. every 5 minutes) to
|
||||
keep your database in sync with ours.</p>
|
||||
|
||||
<p>For some applications it might be desireable to have a quick access to the entire
|
||||
Opencaching database (instead of querying for specific portions of it). You may use
|
||||
OKAPI's <b>replicate</b> module to achive this effect. The <b>changelog</b> method
|
||||
is the primary replication service which you will use. However, to correctly set up
|
||||
your first database copy, you will need to use the <b>fulldump</b> method.</p>
|
||||
|
||||
<p>A couple of things for you to remember:</p>
|
||||
<ul>
|
||||
<li>You <b>must</b> update your database frequently for this method to work.
|
||||
We don't keep the changelog indefinitelly. You must update at least once a week!</li>
|
||||
|
||||
<li>You <b>should not</b> update your database more frequently than once per
|
||||
5 minutes. This could kill our servers, and it wouldn't do you any good, since
|
||||
we update the changelog only once every 5 minutes anyway.</li>
|
||||
</ul>
|
||||
|
||||
<p>Let's assume that you already have a copy of OKAPI database, but it's
|
||||
already 2 days old. You want to use the <b>changelog</b> method to update
|
||||
your copy to the most current state.</p>
|
||||
|
||||
<p>Changelog is the list of all changes which appeared in the OKAPI database
|
||||
since the last time you downloaded it. What you have to do is to download this
|
||||
list of changes and to replay them on your copy of our database. After you do
|
||||
this, your database is up-to-date.</p>
|
||||
|
||||
<p>We use <b>revision</b> numbers to keep track of all the versions of the
|
||||
database. Every time we update a database, the <b>revision</b> is increased.
|
||||
You will also receive this number every time you fetch a changelog or a fulldump
|
||||
of our database. You must keep this number carefully, because you need
|
||||
it in order for us to generate a proper changelog for you next time you ask
|
||||
for it!</p>
|
||||
|
||||
<p><b>Example.</b> This is a valid list of requests you should issue and their
|
||||
responses:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>fulldump</b> - you receive a fulldump of our database with the
|
||||
revision number 238004. <b>You will call this method only once</b> (to
|
||||
initiate your copy of the database).</li>
|
||||
|
||||
<li><b>changelog</b>?since=238004 - OKAPI checks if there were any changes
|
||||
recorded since revision 238004. It responds with the list of changes and the
|
||||
new revision number 238017. You replay the changes on your database.</li>
|
||||
|
||||
<li>You wait for some time between requesting the changelog again.</li>
|
||||
|
||||
<li>Upon your next update, you'll ask for <b>changelog</b>?since=238017, etc.</li>
|
||||
</ul>
|
||||
</desc>
|
||||
<req name='since'>
|
||||
<p>Current revision of your database. This should be the same as the value
|
||||
of <b>revision</b> attribute, which you received with your previous update.</p>
|
||||
|
||||
<p>Old revisions are deleted, the <b>since</b> argument MUST referer to a revision no older
|
||||
than 10 days. You will have to download a fulldump if you have an older copy
|
||||
(shame on you!).</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><b>changelog</b> - a <b>list</b> of dictionaries. Each dictionary has the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><b>object_type</b> - string, object type to which the change refers to. One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>geocache</b> - this change refers to a geocache object,</li>
|
||||
<li><b>log_entry</b> - this change refers to a log entry.</li>
|
||||
</ul>
|
||||
<p>More object types will come in the future. You should ignore all changelog
|
||||
entries with an unknown object_type.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>object_key</b> - a dictionary of fields which compose the primary key for the object.
|
||||
This will be the <b>code</b> field for the <b>geocache</b> object, and <b>uuid</b> field
|
||||
for the <b>log_entry</b> object.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>change_type</b> - string, the type of the change. One of the following values:</p>
|
||||
<ul>
|
||||
<li><b>replace</b> - the object was inserted or updated. You should check if you
|
||||
already have the object in your database. If you have it, you should update its
|
||||
fields accordingly. If you don't, you should create it.</li>
|
||||
<li><b>delete</b> - the object was deleted. You should check if you already have
|
||||
the object in your database. If you do, you should delete it.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>data</b> - a dictionary of fields associated with the object (present only
|
||||
if <b>change_type</b> equals <b>replace</b>).</p>
|
||||
<ul>
|
||||
<li>For <b>geocache</b> objects, this might be any subset of fields described
|
||||
in the services/caches/geocache method. Note that not all of these fields will
|
||||
be included here (i.e. latest_logs will not).</li>
|
||||
<li>For <b>log_entry</b> objects, this might be any subset of fields described
|
||||
in the services/logs/logs method, <b>plus</b> additional <b>cache_code</b> field,
|
||||
the code of the geocache to which the log entry refers to.</li>
|
||||
</ul>
|
||||
<p>In theory this dictionary should contain only these fields which actually changed.
|
||||
In truth, it MAY contain all the other fields too. This behavior may change in future.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>You should iterate through this changelog sequentially. All the changes should be applied
|
||||
in the same order as they were listed in the changelog. Single object may appear multiple times
|
||||
inside the changelog. Changelog will contain all the changes which occured since the time you
|
||||
specified in the <b>since</b> parameter and it MAY contain some more, which were submitted
|
||||
<b>before</b> this date (see below). The changes which are unnecessary MAY be skipped (ex. when
|
||||
cache description changes multiple times, we may want to include only the last change).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>revision</b> - this is the revision number which you should use in the <b>since</b> parameter
|
||||
when you call this method next time.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>more</b> - boolean. If <b>false</b>, then it means that the entire changelog had been
|
||||
pulled. If <b>true</b>, then there are more items waiting to be pulled - you should rerun this
|
||||
method again (with the value of <b>revision</b> inserted in the <b>since</b> parameter).</p>
|
||||
<p>The changelog is usually tiny, but it also might be huge at times. It may even
|
||||
contain all the caches in the database (i.e. if we decide to do some changes on all
|
||||
caches in a bulk). This is the reason why we introduced the <b>more</b> attribute. It makes it
|
||||
easier to parse the changelog sequentially.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>The response MAY contain changes recorded before the revision which you stated in your <b>since</b>
|
||||
parameter. This is due to caching. If we already have a response ready, that was produced for a
|
||||
"since" parameter which was a little more in the past, we may want to return this cached copy,
|
||||
instead of producing a new one. It will be faster for us, and you shouldn't even notice. We will
|
||||
still make sure to set the <b>revision</b> and <b>more</b> attributes in a correct way, which
|
||||
in turn will make you query us again, if you need to.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -14,67 +14,67 @@ use okapi\BadRequest;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
private static function count_calls($consumer_key, $days)
|
||||
{
|
||||
return (
|
||||
Db::select_value("
|
||||
select count(*)
|
||||
from okapi_stats_temp
|
||||
where
|
||||
consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
||||
and service_name='services/replicate/fulldump'
|
||||
")
|
||||
+
|
||||
Db::select_value("
|
||||
select sum(total_calls)
|
||||
from okapi_stats_hourly
|
||||
where
|
||||
consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
||||
and service_name='services/replicate/fulldump'
|
||||
and period_start > date_add(now(), interval -$days day)
|
||||
limit 1
|
||||
")
|
||||
);
|
||||
}
|
||||
private static function count_calls($consumer_key, $days)
|
||||
{
|
||||
return (
|
||||
Db::select_value("
|
||||
select count(*)
|
||||
from okapi_stats_temp
|
||||
where
|
||||
consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
||||
and service_name='services/replicate/fulldump'
|
||||
")
|
||||
+
|
||||
Db::select_value("
|
||||
select sum(total_calls)
|
||||
from okapi_stats_hourly
|
||||
where
|
||||
consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
||||
and service_name='services/replicate/fulldump'
|
||||
and period_start > date_add(now(), interval -$days day)
|
||||
limit 1
|
||||
")
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
|
||||
$data = Cache::get("last_fulldump");
|
||||
if ($data == null)
|
||||
throw new BadRequest("No fulldump found. Try again later. If this doesn't help ".
|
||||
"contact site administrator and/or OKAPI developers.");
|
||||
$data = Cache::get("last_fulldump");
|
||||
if ($data == null)
|
||||
throw new BadRequest("No fulldump found. Try again later. If this doesn't help ".
|
||||
"contact site administrator and/or OKAPI developers.");
|
||||
|
||||
# Check consumer's quota
|
||||
# Check consumer's quota
|
||||
|
||||
$please = $request->get_parameter('pleeaase');
|
||||
if ($please != 'true')
|
||||
{
|
||||
$not_good = 3 < self::count_calls($request->consumer->key, 30);
|
||||
if ($not_good)
|
||||
throw new BadRequest("Consumer's monthly quota exceeded. Try later or call with '&pleeaase=true'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
$not_good = 5 < self::count_calls($request->consumer->key, 1);
|
||||
if ($not_good)
|
||||
throw new BadRequest("No more please. Seriously, dude...");
|
||||
}
|
||||
$please = $request->get_parameter('pleeaase');
|
||||
if ($please != 'true')
|
||||
{
|
||||
$not_good = 3 < self::count_calls($request->consumer->key, 30);
|
||||
if ($not_good)
|
||||
throw new BadRequest("Consumer's monthly quota exceeded. Try later or call with '&pleeaase=true'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
$not_good = 5 < self::count_calls($request->consumer->key, 1);
|
||||
if ($not_good)
|
||||
throw new BadRequest("No more please. Seriously, dude...");
|
||||
}
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = $data['meta']['content_type'];
|
||||
$response->content_disposition = 'attachment; filename="'.$data['meta']['public_filename'].'"';
|
||||
$response->stream_length = $data['meta']['compressed_size'];
|
||||
$response->body = fopen($data['meta']['filepath'], "rb");
|
||||
$response->allow_gzip = false;
|
||||
return $response;
|
||||
}
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = $data['meta']['content_type'];
|
||||
$response->content_disposition = 'attachment; filename="'.$data['meta']['public_filename'].'"';
|
||||
$response->stream_length = $data['meta']['compressed_size'];
|
||||
$response->body = fopen($data['meta']['filepath'], "rb");
|
||||
$response->allow_gzip = false;
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -1,63 +1,68 @@
|
||||
<xml>
|
||||
<brief>Download OKAPI database snapshot</brief>
|
||||
<issue-id>110</issue-id>
|
||||
<desc>
|
||||
<p>Download the latest snapshot of OKAPI database. You should call this method
|
||||
only once.</p>
|
||||
|
||||
<p>For some applications it might be desireable to have a quick access to the entire
|
||||
Opencaching database (instead of querying for specific portions of it). You may use
|
||||
OKAPI's <b>replicate</b> module to achive this condition. The <b>changelog</b> method
|
||||
is the primary replication service which you will use. However, to correctly set up
|
||||
your first database copy, you will need to use the <b>fulldump</b> method.</p>
|
||||
<brief>Download OKAPI database snapshot</brief>
|
||||
<issue-id>110</issue-id>
|
||||
<desc>
|
||||
<p>Download the latest snapshot of OKAPI database. You should call this method
|
||||
only once.</p>
|
||||
|
||||
<p><b>Important:</b> There is a remote possibility that this method MAY change in
|
||||
a non-backward-compatible way or it might even get removed. We don't plan on doing
|
||||
this, but we might be forced to (i.e. to prevent abuse).</p>
|
||||
|
||||
<p><b>Note:</b> The cache descriptions will be generated using the <b>attribution_append=static</b>
|
||||
parameter (see the geocache method). Full attributions are not always suitable for replication,
|
||||
since they may contain dates on some installations
|
||||
(<a href='https://code.google.com/p/opencaching-api/issues/detail?id=178'>why?</a>).
|
||||
To make sure that static attributions are enough, consult the local Data
|
||||
Licence (the Sign Up page).</p>
|
||||
|
||||
<p>A couple of things for you to remember:</p>
|
||||
|
||||
<ul>
|
||||
<li>Currently, this functionality is available <b>for developers only</b>,
|
||||
NOT for the individual users. We don't want users to download a fresh snapshot of
|
||||
the entire database every time they want, this could kill our servers.
|
||||
If you want to enable such features for your users, you can do it, but you
|
||||
must use <b>your own server</b> for data traffic (especially, fulldump requests).</li>
|
||||
|
||||
<li>Fulldump is a copy of the entire database. We generate such copy once every couple of
|
||||
days. This copy if intended for you to start only, later you must use the changelog to
|
||||
keep it up-to-date.</li>
|
||||
|
||||
<li>Every time our database is extended (new fields or new object types), and you want to
|
||||
make use of these new fields, you are of course allowed to download a fulldump copy again.</li>
|
||||
|
||||
<li>There is no XMLMAP version of this file.</li>
|
||||
</ul>
|
||||
</desc>
|
||||
<returns>
|
||||
<p>Archive with JSON-encoded files. File named <b>index.json</b> will contain a dictionary
|
||||
of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>revision</b> - revision of the database snapshot contained in the archive,</li>
|
||||
<li><b>data_files</b> - list of filenames which contain the changelog entries for
|
||||
you to parse. Each file contains a JSON-encoded list of changelog entries, in format
|
||||
described in the <b>changelog</b> method ("replace" only).</li>
|
||||
<li><b>meta</b> - a dictionary of other meta data, not important.</li>
|
||||
</ul>
|
||||
<p>Note: We use TGZ or TBZ2 format to encode this archive:</p>
|
||||
<ul>
|
||||
<li><b>TGZ</b> archive (more commonly known as <b>.tar.gz</b> archive) is a TAR
|
||||
archive compressed with GZIP.</li>
|
||||
<li><b>TBZ2</b> archive (more commonly known as <b>.tar.bz2</b> archive) is a TAR
|
||||
archive compressed with BZIP2.</li>
|
||||
</ul>
|
||||
<p>There are many tools available for handling these archives. In Linux, try "tar -xf filename".</p>
|
||||
</returns>
|
||||
<p>For some applications it might be desireable to have a quick access to the entire
|
||||
Opencaching database (instead of querying for specific portions of it). You may use
|
||||
OKAPI's <b>replicate</b> module to achive this state. The <b>changelog</b> method
|
||||
is the primary replication service which you will use. However, to correctly set up
|
||||
your first database copy, you will need to use the <b>fulldump</b> method.</p>
|
||||
|
||||
<p>A couple of things for you to remember:</p>
|
||||
|
||||
<ul>
|
||||
<li>Currently, this method is available <b>for developers only</b>,
|
||||
not for the individual users. We don't want users to download a fresh snapshot of
|
||||
the entire database every time they want, this could kill our servers.
|
||||
If you want to enable such features for your users, you can do it, but you
|
||||
must use <b>your own server</b> for serving fulldump requests. (You don't
|
||||
have to use your server to relay changelog requests.)</li>
|
||||
|
||||
<li>Fulldump is a copy of the entire database. We generate such copy once every couple of
|
||||
days. This copy if intended for you to make a fresh start only. Later, you
|
||||
must use the <b>changelog</b> method to keep your data up-to-date.</li>
|
||||
|
||||
<li>Every time our database is extended (new fields or new object types), and you want to
|
||||
make use of these new fields, you are of course allowed to download a fulldump copy again.</li>
|
||||
|
||||
<li>There is no XMLMAP version of this file. JSON only.</li>
|
||||
</ul>
|
||||
|
||||
<p><b>Additional notes on data attribution:</b> Cache descriptions will be
|
||||
generated using the <b>attribution_append=static</b> parameter (see the
|
||||
geocache method). This is because the full attributions are not always suitable
|
||||
for replication, since they may contain dynamically changing dates on some
|
||||
installations (<a href='https://code.google.com/p/opencaching-api/issues/detail?id=178'>why?</a>).
|
||||
To make sure that static attributions are enough, consult the local Data
|
||||
Licence (the Sign Up page).</p>
|
||||
</desc>
|
||||
<returns>
|
||||
<p>Compressed archive with JSON-encoded files. File named <b>index.json</b> will
|
||||
contain a dictionary of the following structure:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>revision</b> - revision of the database snapshot contained in the archive,</li>
|
||||
|
||||
<li><b>data_files</b> - list of filenames which contain the changelog entries for
|
||||
you to parse. Each file contains a JSON-encoded list of changelog entries, in format
|
||||
described in the <b>changelog</b> method ("replace" only).</li>
|
||||
|
||||
<li><b>meta</b> - a dictionary of other meta data, not important.</li>
|
||||
</ul>
|
||||
|
||||
<p>Note: We use TGZ or TBZ2 format to encode this archive:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>TGZ</b> archive (also known as <b>.tar.gz</b>) is a TAR
|
||||
archive compressed with GZIP.</li>
|
||||
|
||||
<li><b>TBZ2</b> archive (also known as <b>.tar.bz2</b>) is a TAR
|
||||
archive compressed with BZIP2.</li>
|
||||
</ul>
|
||||
|
||||
<p>There are many tools available for handling these archives. In Linux, try "tar -xf filename".</p>
|
||||
</returns>
|
||||
</xml>
|
@ -18,35 +18,35 @@ use okapi\services\replicate\ReplicateCommon;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
|
||||
$result = array();
|
||||
$result['changelog'] = array(
|
||||
'min_since' => ReplicateCommon::get_min_since(),
|
||||
'revision' => ReplicateCommon::get_revision(),
|
||||
);
|
||||
$dump = Cache::get("last_fulldump");
|
||||
if ($dump)
|
||||
{
|
||||
$result['latest_fulldump'] = array(
|
||||
'revision' => $dump['revision'],
|
||||
'generated_at' => $dump['meta']['generated_at'],
|
||||
'size' => $dump['meta']['compressed_size'],
|
||||
'size_uncompressed' => $dump['meta']['uncompressed_size'],
|
||||
);
|
||||
} else {
|
||||
$result['latest_fulldump'] = null;
|
||||
}
|
||||
$result = array();
|
||||
$result['changelog'] = array(
|
||||
'min_since' => ReplicateCommon::get_min_since(),
|
||||
'revision' => ReplicateCommon::get_revision(),
|
||||
);
|
||||
$dump = Cache::get("last_fulldump");
|
||||
if ($dump)
|
||||
{
|
||||
$result['latest_fulldump'] = array(
|
||||
'revision' => $dump['revision'],
|
||||
'generated_at' => $dump['meta']['generated_at'],
|
||||
'size' => $dump['meta']['compressed_size'],
|
||||
'size_uncompressed' => $dump['meta']['uncompressed_size'],
|
||||
);
|
||||
} else {
|
||||
$result['latest_fulldump'] = null;
|
||||
}
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
<xml>
|
||||
<brief>Get information on current changelog and fulldump state</brief>
|
||||
<issue-id>111</issue-id>
|
||||
<desc>
|
||||
<p><b>Beta status.</b> Get information on current changelog and fulldump state.</p>
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><b>changelog</b> - a dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>min_since</b> - the lowest allowed value for the <b>since</b> attribute
|
||||
(the ID of the last changelog entry was already removed from our database),</li>
|
||||
<li><b>revision</b> - the current revision of the database (the ID of the
|
||||
newest changelog entry kept in our database),</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>latest_fulldump</b> - a dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>revision</b> - revision of the database saved in the latest fulldump,</li>
|
||||
<li><b>generated_at</b> - date and time (ISO 8601) when the fulldump was generated,</li>
|
||||
<li><b>size</b> - size of the file, in bytes,</li>
|
||||
<li><b>size_uncompressed</b> - approximate size of the uncompressed contents, in bytes.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</returns>
|
||||
<brief>Get information on current changelog and fulldump state</brief>
|
||||
<issue-id>111</issue-id>
|
||||
<desc>
|
||||
<p><b>Beta status.</b> Get information on current changelog and fulldump state.</p>
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><b>changelog</b> - a dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>min_since</b> - the lowest allowed value for the <b>since</b> attribute
|
||||
(the ID of the last changelog entry was already removed from our database),</li>
|
||||
<li><b>revision</b> - the current revision of the database (the ID of the
|
||||
newest changelog entry kept in our database),</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>latest_fulldump</b> - a dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>revision</b> - revision of the database saved in the latest fulldump,</li>
|
||||
<li><b>generated_at</b> - date and time (ISO 8601) when the fulldump was generated,</li>
|
||||
<li><b>size</b> - size of the file, in bytes,</li>
|
||||
<li><b>size_uncompressed</b> - approximate size of the uncompressed contents, in bytes.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
File diff suppressed because it is too large
Load Diff
@ -13,27 +13,27 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$internal_id = $request->get_parameter('internal_id');
|
||||
if (!$internal_id) throw new ParamMissing('internal_id');
|
||||
$fields = $request->get_parameter('fields');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$internal_id = $request->get_parameter('internal_id');
|
||||
if (!$internal_id) throw new ParamMissing('internal_id');
|
||||
$fields = $request->get_parameter('fields');
|
||||
|
||||
# There's no need to validate the fields parameter.
|
||||
# There's no need to validate the fields parameter.
|
||||
|
||||
$results = OkapiServiceRunner::call('services/users/by_internal_ids', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('internal_ids' => $internal_id,
|
||||
'fields' => $fields)));
|
||||
$result = $results[$internal_id];
|
||||
if ($result == null)
|
||||
throw new InvalidParam('internal_id', "There is no user by this internal_id.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$results = OkapiServiceRunner::call('services/users/by_internal_ids', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('internal_ids' => $internal_id,
|
||||
'fields' => $fields)));
|
||||
$result = $results[$internal_id];
|
||||
if ($result == null)
|
||||
throw new InvalidParam('internal_id', "There is no user by this internal_id.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
<xml>
|
||||
<brief>Find single user, by his internal_id</brief>
|
||||
<issue-id>44</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve information on a single user, referencing him by his <b>internal</b> ID.</p>
|
||||
<p>In general, you should not use this method. Reference your users by their
|
||||
normal ID - <b>user_uuid</b>. Also, internal IDs are not universally unique and are
|
||||
a poor choice for a key.</p>
|
||||
</desc>
|
||||
<req name='internal_id'>Internal ID</req>
|
||||
<req name='fields'>
|
||||
<p>See services/users/user method.</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>See services/users/user method.</p>
|
||||
</returns>
|
||||
<brief>Find single user, by his internal_id</brief>
|
||||
<issue-id>44</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve information on a single user, referencing him by his <b>internal</b> ID.</p>
|
||||
<p>In general, you should not use this method. Reference your users by their
|
||||
normal ID - <b>user_uuid</b>. Also, internal IDs are not universally unique and are
|
||||
a poor choice for a key.</p>
|
||||
</desc>
|
||||
<req name='internal_id'>Internal ID</req>
|
||||
<req name='fields'>
|
||||
<p>See services/users/user method.</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>See services/users/user method.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -13,56 +13,56 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$internal_ids = $request->get_parameter('internal_ids');
|
||||
if (!$internal_ids) throw new ParamMissing('internal_ids');
|
||||
$internal_ids = explode("|", $internal_ids);
|
||||
if (count($internal_ids) > 500)
|
||||
throw new InvalidParam('internal_ids', "Maximum allowed number of referenced users ".
|
||||
"is 500. You provided ".count($internal_ids)." references.");
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields)
|
||||
throw new ParamMissing('fields');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$internal_ids = $request->get_parameter('internal_ids');
|
||||
if (!$internal_ids) throw new ParamMissing('internal_ids');
|
||||
$internal_ids = explode("|", $internal_ids);
|
||||
if (count($internal_ids) > 500)
|
||||
throw new InvalidParam('internal_ids', "Maximum allowed number of referenced users ".
|
||||
"is 500. You provided ".count($internal_ids)." references.");
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields)
|
||||
throw new ParamMissing('fields');
|
||||
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
|
||||
$rs = Db::query("
|
||||
select user_id, uuid
|
||||
from user
|
||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', $internal_ids))."')
|
||||
");
|
||||
$internalid2useruuid = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$internalid2useruuid[$row['user_id']] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
$rs = Db::query("
|
||||
select user_id, uuid
|
||||
from user
|
||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', $internal_ids))."')
|
||||
");
|
||||
$internalid2useruuid = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$internalid2useruuid[$row['user_id']] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
# Retrieve data on given user_uuids.
|
||||
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($internalid2useruuid)),
|
||||
'fields' => $fields)));
|
||||
# Retrieve data on given user_uuids.
|
||||
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($internalid2useruuid)),
|
||||
'fields' => $fields)));
|
||||
|
||||
# Map user_uuids to internal_ids. Also check which internal_ids were not found
|
||||
# and mark them with null.
|
||||
$results = array();
|
||||
foreach ($internal_ids as $internal_id)
|
||||
{
|
||||
if (!isset($internalid2useruuid[$internal_id]))
|
||||
$results[$internal_id] = null;
|
||||
else
|
||||
$results[$internal_id] = $id_results[$internalid2useruuid[$internal_id]];
|
||||
}
|
||||
# Map user_uuids to internal_ids. Also check which internal_ids were not found
|
||||
# and mark them with null.
|
||||
$results = array();
|
||||
foreach ($internal_ids as $internal_id)
|
||||
{
|
||||
if (!isset($internalid2useruuid[$internal_id]))
|
||||
$results[$internal_id] = null;
|
||||
else
|
||||
$results[$internal_id] = $id_results[$internalid2useruuid[$internal_id]];
|
||||
}
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
<xml>
|
||||
<brief>Find multiple users, by their internal IDs</brief>
|
||||
<issue-id>45</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the services/users/by_internal_id method, but works
|
||||
with multiple users (instead of only one).</p>
|
||||
</desc>
|
||||
<req name='internal_ids'>
|
||||
<p>Pipe-separated list of internal user IDs. No more than 500 are allowed.</p>
|
||||
</req>
|
||||
<req name='fields'>
|
||||
<p>See services/users/user method.</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. Internal IDs you provide will be mapped to dictionary keys,
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given internal ID haven't been found.</p>
|
||||
</returns>
|
||||
<brief>Find multiple users, by their internal IDs</brief>
|
||||
<issue-id>45</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the services/users/by_internal_id method, but works
|
||||
with multiple users (instead of only one).</p>
|
||||
</desc>
|
||||
<req name='internal_ids'>
|
||||
<p>Pipe-separated list of internal user IDs. No more than 500 are allowed.</p>
|
||||
</req>
|
||||
<req name='fields'>
|
||||
<p>See services/users/user method.</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. Internal IDs you provide will be mapped to dictionary keys,
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given internal ID haven't been found.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -16,27 +16,27 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$username = $request->get_parameter('username');
|
||||
if (!$username) throw new ParamMissing('username');
|
||||
$fields = $request->get_parameter('fields');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$username = $request->get_parameter('username');
|
||||
if (!$username) throw new ParamMissing('username');
|
||||
$fields = $request->get_parameter('fields');
|
||||
|
||||
# There's no need to validate the fields parameter.
|
||||
# There's no need to validate the fields parameter.
|
||||
|
||||
$results = OkapiServiceRunner::call('services/users/by_usernames', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('usernames' => $username,
|
||||
'fields' => $fields)));
|
||||
$result = $results[$username];
|
||||
if ($result == null)
|
||||
throw new InvalidParam('username', "There is no user by this username.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$results = OkapiServiceRunner::call('services/users/by_usernames', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('usernames' => $username,
|
||||
'fields' => $fields)));
|
||||
$result = $results[$username];
|
||||
if ($result == null)
|
||||
throw new InvalidParam('username', "There is no user by this username.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
<xml>
|
||||
<brief>Find single user, by his/her username</brief>
|
||||
<issue-id>24</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve information on a single user, referencing him by his username.</p>
|
||||
<p><b>IMPORTANT:</b> user IDs don't change, but usernames <b>may</b> change.</p>
|
||||
<p>Usually, you'll want to run this method only once, in order to get the IDs
|
||||
of referenced users. You should not store usernames in your database, it is
|
||||
much safer to reference them by their IDs.</p>
|
||||
</desc>
|
||||
<req name='username'>Name of the user (case insensitive).</req>
|
||||
<req name='fields'>
|
||||
<p>Same as in the services/users/user method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/users/user method for a list available values.</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected.</p>
|
||||
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
<brief>Find single user, by his/her username</brief>
|
||||
<issue-id>24</issue-id>
|
||||
<desc>
|
||||
<p>Retrieve information on a single user, referencing him by his username.</p>
|
||||
<p><b>IMPORTANT:</b> user IDs don't change, but usernames <b>may</b> change.</p>
|
||||
<p>Usually, you'll want to run this method only once, in order to get the IDs
|
||||
of referenced users. You should not store usernames in your database, it is
|
||||
much safer to reference them by their IDs.</p>
|
||||
</desc>
|
||||
<req name='username'>Name of the user (case insensitive).</req>
|
||||
<req name='fields'>
|
||||
<p>Same as in the services/users/user method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/users/user method for a list available values.</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected.</p>
|
||||
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -13,63 +13,63 @@ use okapi\OkapiInternalRequest;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$usernames = $request->get_parameter('usernames');
|
||||
if (!$usernames) throw new ParamMissing('usernames');
|
||||
$usernames = explode("|", $usernames);
|
||||
if (count($usernames) > 500)
|
||||
throw new InvalidParam('usernames', "Maximum allowed number of referenced users ".
|
||||
"is 500. You provided ".count($usernames)." usernames.");
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields)
|
||||
throw new ParamMissing('fields');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$usernames = $request->get_parameter('usernames');
|
||||
if (!$usernames) throw new ParamMissing('usernames');
|
||||
$usernames = explode("|", $usernames);
|
||||
if (count($usernames) > 500)
|
||||
throw new InvalidParam('usernames', "Maximum allowed number of referenced users ".
|
||||
"is 500. You provided ".count($usernames)." usernames.");
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields)
|
||||
throw new ParamMissing('fields');
|
||||
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
|
||||
$rs = Db::query("
|
||||
select username, uuid
|
||||
from user
|
||||
where username collate utf8_general_ci in ('".implode("','", array_map('mysql_real_escape_string', $usernames))."')
|
||||
");
|
||||
$lower_username2useruuid = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$lower_username2useruuid[mb_strtolower($row['username'], 'utf-8')] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
$rs = Db::query("
|
||||
select username, uuid
|
||||
from user
|
||||
where username collate utf8_general_ci in ('".implode("','", array_map('mysql_real_escape_string', $usernames))."')
|
||||
");
|
||||
$lower_username2useruuid = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$lower_username2useruuid[mb_strtolower($row['username'], 'utf-8')] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
# Retrieve data for the found user_uuids.
|
||||
# Retrieve data for the found user_uuids.
|
||||
|
||||
if (count($lower_username2useruuid) > 0)
|
||||
{
|
||||
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($lower_username2useruuid)),
|
||||
'fields' => $fields)));
|
||||
} else {
|
||||
$id_results = array();
|
||||
}
|
||||
if (count($lower_username2useruuid) > 0)
|
||||
{
|
||||
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($lower_username2useruuid)),
|
||||
'fields' => $fields)));
|
||||
} else {
|
||||
$id_results = array();
|
||||
}
|
||||
|
||||
# Map user_uuids back to usernames. Also check which usernames were not found
|
||||
# and mark them with null.
|
||||
# Map user_uuids back to usernames. Also check which usernames were not found
|
||||
# and mark them with null.
|
||||
|
||||
$results = array();
|
||||
foreach ($usernames as $username)
|
||||
{
|
||||
if (!isset($lower_username2useruuid[mb_strtolower($username, 'utf-8')]))
|
||||
$results[$username] = null;
|
||||
else
|
||||
$results[$username] = $id_results[$lower_username2useruuid[mb_strtolower($username, 'utf-8')]];
|
||||
}
|
||||
$results = array();
|
||||
foreach ($usernames as $username)
|
||||
{
|
||||
if (!isset($lower_username2useruuid[mb_strtolower($username, 'utf-8')]))
|
||||
$results[$username] = null;
|
||||
else
|
||||
$results[$username] = $id_results[$lower_username2useruuid[mb_strtolower($username, 'utf-8')]];
|
||||
}
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
<xml>
|
||||
<brief>Find multiple users, by their usernames</brief>
|
||||
<issue-id>25</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the services/users/by_username method, but works
|
||||
with multiple users (instead of only one).</p>
|
||||
</desc>
|
||||
<req name='usernames'>
|
||||
<p>Pipe-separated list of usernames. No more than 500 are allowed.</p>
|
||||
</req>
|
||||
<req name='fields'>
|
||||
<p>Same as in the services/users/user method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/users/user method for a list available values.</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. Usernames you provide will be mapped to dictionary keys,
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given user haven't been found.
|
||||
(This behavior is different than in the services/users/by_username method, which
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
<brief>Find multiple users, by their usernames</brief>
|
||||
<issue-id>25</issue-id>
|
||||
<desc>
|
||||
<p>This method works like the services/users/by_username method, but works
|
||||
with multiple users (instead of only one).</p>
|
||||
</desc>
|
||||
<req name='usernames'>
|
||||
<p>Pipe-separated list of usernames. No more than 500 are allowed.</p>
|
||||
</req>
|
||||
<req name='fields'>
|
||||
<p>Same as in the services/users/user method. Pipe-separated list
|
||||
of field names which you are interested with.
|
||||
See services/users/user method for a list available values.</p>
|
||||
</req>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary. Usernames you provide will be mapped to dictionary keys,
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given user haven't been found.
|
||||
(This behavior is different than in the services/users/by_username method, which
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
</xml>
|
@ -16,41 +16,41 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
if (!$user_uuid)
|
||||
{
|
||||
if ($request->token)
|
||||
{
|
||||
$tmp = OkapiServiceRunner::call('services/users/by_internal_id', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('internal_id' => $request->token->user_id, 'fields' => 'uuid')));
|
||||
$user_uuid = $tmp['uuid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BadRequest("You must either: 1. supply the user_uuid argument, or "
|
||||
."2. sign your request with an Access Token.");
|
||||
}
|
||||
}
|
||||
$fields = $request->get_parameter('fields');
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
if (!$user_uuid)
|
||||
{
|
||||
if ($request->token)
|
||||
{
|
||||
$tmp = OkapiServiceRunner::call('services/users/by_internal_id', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('internal_id' => $request->token->user_id, 'fields' => 'uuid')));
|
||||
$user_uuid = $tmp['uuid'];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BadRequest("You must either: 1. supply the user_uuid argument, or "
|
||||
."2. sign your request with an Access Token.");
|
||||
}
|
||||
}
|
||||
$fields = $request->get_parameter('fields');
|
||||
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
|
||||
$results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => $user_uuid,
|
||||
'fields' => $fields)));
|
||||
$result = $results[$user_uuid];
|
||||
if ($result == null)
|
||||
throw new InvalidParam('user_uuid', "There is no user by this ID.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
$results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => $user_uuid,
|
||||
'fields' => $fields)));
|
||||
$result = $results[$user_uuid];
|
||||
if ($result == null)
|
||||
throw new InvalidParam('user_uuid', "There is no user by this ID.");
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,45 @@
|
||||
<xml>
|
||||
<brief>Retrieve information on a single user</brief>
|
||||
<issue-id>26</issue-id>
|
||||
<desc>
|
||||
Retrieve information on a single user. This method might be also used
|
||||
to retrieve data of the user in who's name the Access Token have been
|
||||
issued. To do this, include the Access Token in your request, and <b>don't</b>
|
||||
include the user_uuid argument.
|
||||
</desc>
|
||||
<req name='fields'>
|
||||
<p>Pipe-separated list of field names which you are interested with.
|
||||
Selected fields will be included in the response. See below for the
|
||||
list of available fields.</p>
|
||||
</req>
|
||||
<opt name='user_uuid'>
|
||||
<p>ID of the user.</p>
|
||||
<p>This parameter is optional only when you sign your
|
||||
request with an Access Token (Level 3 Authentication). Otherwise,
|
||||
it is <b>required</b>.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>uuid</b> - ID of the user,</li>
|
||||
<li><b>username</b> - username (login) of the user,</li>
|
||||
<li><b>profile_url</b> - URL of the user's Opencaching profile page,</li>
|
||||
<li>
|
||||
<p><b>is_admin</b> - boolean; true is user has admin privileges.</p>
|
||||
<p>This value can be accessed only with <b>Level 3</b> Authentication
|
||||
and only for the user of your Access Token. For all other reads, is_admin
|
||||
will equal <b>null</b>.</p>
|
||||
</li>
|
||||
<li><b>internal_id</b> - internal ID of the user (<b>DO NOT</b> use this!
|
||||
use the <b>uuid</b> as the user identifier),</li>
|
||||
<li><b>caches_found</b> - number of "Found it" and "Attended" log entries,</li>
|
||||
<li><b>caches_notfound</b> - number of "Didn't find it" log entries,</li>
|
||||
<li><b>caches_hidden</b> - number of caches owned,</li>
|
||||
<li><b>rcmds_given</b> - number of recommendations given.</li>
|
||||
</ul>
|
||||
|
||||
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
<brief>Retrieve information on a single user</brief>
|
||||
<issue-id>26</issue-id>
|
||||
<desc>
|
||||
Retrieve information on a single user. This method might be also used
|
||||
to retrieve data of the user in who's name the Access Token have been
|
||||
issued. To do this, include the Access Token in your request, and <b>don't</b>
|
||||
include the user_uuid argument.
|
||||
</desc>
|
||||
<req name='fields'>
|
||||
<p>Pipe-separated list of field names which you are interested with.
|
||||
Selected fields will be included in the response. See below for the
|
||||
list of available fields.</p>
|
||||
</req>
|
||||
<opt name='user_uuid'>
|
||||
<p>ID of the user.</p>
|
||||
<p>This parameter is optional only when you sign your
|
||||
request with an Access Token (Level 3 Authentication). Otherwise,
|
||||
it is <b>required</b>.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>uuid</b> - ID of the user,</li>
|
||||
<li><b>username</b> - username (login) of the user,</li>
|
||||
<li><b>profile_url</b> - URL of the user's Opencaching profile page,</li>
|
||||
<li>
|
||||
<p><b>is_admin</b> - boolean; true is user has admin privileges.</p>
|
||||
<p>This value can be accessed only with <b>Level 3</b> Authentication
|
||||
and only for the user of your Access Token. For all other reads, is_admin
|
||||
will equal <b>null</b>.</p>
|
||||
</li>
|
||||
<li><b>internal_id</b> - internal ID of the user (<b>DO NOT</b> use this!
|
||||
use the <b>uuid</b> as the user identifier),</li>
|
||||
<li><b>caches_found</b> - number of "Found it" and "Attended" log entries,</li>
|
||||
<li><b>caches_notfound</b> - number of "Didn't find it" log entries,</li>
|
||||
<li><b>caches_hidden</b> - number of caches owned,</li>
|
||||
<li><b>rcmds_given</b> - number of recommendations given.</li>
|
||||
</ul>
|
||||
|
||||
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
</xml>
|
@ -13,154 +13,154 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
private static $valid_field_names = array('uuid', 'username', 'profile_url', 'internal_id', 'is_admin',
|
||||
'caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given');
|
||||
private static $valid_field_names = array('uuid', 'username', 'profile_url', 'internal_id', 'is_admin',
|
||||
'caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given');
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$user_uuids = $request->get_parameter('user_uuids');
|
||||
if (!$user_uuids) throw new ParamMissing('user_uuids');
|
||||
$user_uuids = explode("|", $user_uuids);
|
||||
if (count($user_uuids) > 500)
|
||||
throw new InvalidParam('user_uuids', "Maximum allowed number of referenced users ".
|
||||
"is 500. You provided ".count($user_uuids)." user IDs.");
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields)
|
||||
throw new ParamMissing('fields');
|
||||
$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.");
|
||||
$rs = Db::query("
|
||||
select user_id, uuid, username, admin
|
||||
from user
|
||||
where uuid in ('".implode("','", array_map('mysql_real_escape_string', $user_uuids))."')
|
||||
");
|
||||
$results = array();
|
||||
$id2uuid = array();
|
||||
$uuid2id = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$id2uuid[$row['user_id']] = $row['uuid'];
|
||||
$uuid2id[$row['uuid']] = $row['user_id'];
|
||||
$entry = array();
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
switch ($field)
|
||||
{
|
||||
case 'uuid': $entry['uuid'] = $row['uuid']; break;
|
||||
case 'username': $entry['username'] = $row['username']; break;
|
||||
case 'profile_url': $entry['profile_url'] = Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id']; break;
|
||||
case 'is_admin':
|
||||
if (!$request->token) {
|
||||
$entry['is_admin'] = null;
|
||||
} elseif ($request->token->user_id != $row['user_id']) {
|
||||
$entry['is_admin'] = null;
|
||||
} else {
|
||||
$entry['is_admin'] = $row['admin'] ? true : false;
|
||||
}
|
||||
break;
|
||||
case 'internal_id': $entry['internal_id'] = $row['user_id']; break;
|
||||
case 'caches_found': /* handled separately */ break;
|
||||
case 'caches_notfound': /* handled separately */ break;
|
||||
case 'caches_hidden': /* handled separately */ break;
|
||||
case 'rcmds_given': /* handled separately */ break;
|
||||
default: throw new Exception("Missing field case: ".$field);
|
||||
}
|
||||
}
|
||||
$results[$row['uuid']] = $entry;
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$user_uuids = $request->get_parameter('user_uuids');
|
||||
if (!$user_uuids) throw new ParamMissing('user_uuids');
|
||||
$user_uuids = explode("|", $user_uuids);
|
||||
if (count($user_uuids) > 500)
|
||||
throw new InvalidParam('user_uuids', "Maximum allowed number of referenced users ".
|
||||
"is 500. You provided ".count($user_uuids)." user IDs.");
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields)
|
||||
throw new ParamMissing('fields');
|
||||
$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.");
|
||||
$rs = Db::query("
|
||||
select user_id, uuid, username, admin
|
||||
from user
|
||||
where uuid in ('".implode("','", array_map('mysql_real_escape_string', $user_uuids))."')
|
||||
");
|
||||
$results = array();
|
||||
$id2uuid = array();
|
||||
$uuid2id = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$id2uuid[$row['user_id']] = $row['uuid'];
|
||||
$uuid2id[$row['uuid']] = $row['user_id'];
|
||||
$entry = array();
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
switch ($field)
|
||||
{
|
||||
case 'uuid': $entry['uuid'] = $row['uuid']; break;
|
||||
case 'username': $entry['username'] = $row['username']; break;
|
||||
case 'profile_url': $entry['profile_url'] = Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id']; break;
|
||||
case 'is_admin':
|
||||
if (!$request->token) {
|
||||
$entry['is_admin'] = null;
|
||||
} elseif ($request->token->user_id != $row['user_id']) {
|
||||
$entry['is_admin'] = null;
|
||||
} else {
|
||||
$entry['is_admin'] = $row['admin'] ? true : false;
|
||||
}
|
||||
break;
|
||||
case 'internal_id': $entry['internal_id'] = $row['user_id']; break;
|
||||
case 'caches_found': /* handled separately */ break;
|
||||
case 'caches_notfound': /* handled separately */ break;
|
||||
case 'caches_hidden': /* handled separately */ break;
|
||||
case 'rcmds_given': /* handled separately */ break;
|
||||
default: throw new Exception("Missing field case: ".$field);
|
||||
}
|
||||
}
|
||||
$results[$row['uuid']] = $entry;
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
# caches_found, caches_notfound, caches_hidden
|
||||
# caches_found, caches_notfound, caches_hidden
|
||||
|
||||
if (in_array('caches_found', $fields) || in_array('caches_notfound', $fields) || in_array('caches_hidden', $fields)
|
||||
|| in_array('rcmds_given', $fields))
|
||||
{
|
||||
# We will load all these stats together. Then we may remove these which
|
||||
# the user doesn't need.
|
||||
if (in_array('caches_found', $fields) || in_array('caches_notfound', $fields) || in_array('caches_hidden', $fields)
|
||||
|| in_array('rcmds_given', $fields))
|
||||
{
|
||||
# We will load all these stats together. Then we may remove these which
|
||||
# the user doesn't need.
|
||||
|
||||
$extras = array();
|
||||
$extras = array();
|
||||
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
{
|
||||
# OCPL stores user stats in 'user' table.
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
{
|
||||
# OCPL stores user stats in 'user' table.
|
||||
|
||||
$rs = Db::query("
|
||||
select user_id, founds_count, notfounds_count, hidden_count
|
||||
from user
|
||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||
");
|
||||
}
|
||||
else
|
||||
{
|
||||
# OCDE stores user stats in 'stat_user' table.
|
||||
$rs = Db::query("
|
||||
select user_id, founds_count, notfounds_count, hidden_count
|
||||
from user
|
||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||
");
|
||||
}
|
||||
else
|
||||
{
|
||||
# OCDE stores user stats in 'stat_user' table.
|
||||
|
||||
$rs = Db::query("
|
||||
select
|
||||
u.user_id,
|
||||
ifnull(su.found, 0) as founds_count,
|
||||
ifnull(su.notfound, 0) as notfounds_count,
|
||||
ifnull(su.hidden, 0) as hidden_count
|
||||
from
|
||||
user u
|
||||
left join stat_user su
|
||||
on su.user_id = u.user_id
|
||||
where u.user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||
");
|
||||
}
|
||||
$rs = Db::query("
|
||||
select
|
||||
u.user_id,
|
||||
ifnull(su.found, 0) as founds_count,
|
||||
ifnull(su.notfound, 0) as notfounds_count,
|
||||
ifnull(su.hidden, 0) as hidden_count
|
||||
from
|
||||
user u
|
||||
left join stat_user su
|
||||
on su.user_id = u.user_id
|
||||
where u.user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||
");
|
||||
}
|
||||
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$extras[$row['user_id']] = array();;
|
||||
$extra_ref = &$extras[$row['user_id']];
|
||||
$extra_ref['caches_found'] = 0 + $row['founds_count'];
|
||||
$extra_ref['caches_notfound'] = 0 + $row['notfounds_count'];
|
||||
$extra_ref['caches_hidden'] = 0 + $row['hidden_count'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$extras[$row['user_id']] = array();;
|
||||
$extra_ref = &$extras[$row['user_id']];
|
||||
$extra_ref['caches_found'] = 0 + $row['founds_count'];
|
||||
$extra_ref['caches_notfound'] = 0 + $row['notfounds_count'];
|
||||
$extra_ref['caches_hidden'] = 0 + $row['hidden_count'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
if (in_array('rcmds_given', $fields))
|
||||
{
|
||||
$rs = Db::query("
|
||||
select user_id, count(*) as rcmds_given
|
||||
from cache_rating
|
||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||
group by user_id
|
||||
");
|
||||
$rcmds_counts = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$rcmds_counts[$row['user_id']] = $row['rcmds_given'];
|
||||
foreach ($extras as $user_id => &$extra_ref)
|
||||
{
|
||||
$extra_ref['rcmds_given'] = isset($rcmds_counts[$user_id]) ? 0 + $rcmds_counts[$user_id] : 0;
|
||||
}
|
||||
}
|
||||
if (in_array('rcmds_given', $fields))
|
||||
{
|
||||
$rs = Db::query("
|
||||
select user_id, count(*) as rcmds_given
|
||||
from cache_rating
|
||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||
group by user_id
|
||||
");
|
||||
$rcmds_counts = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$rcmds_counts[$row['user_id']] = $row['rcmds_given'];
|
||||
foreach ($extras as $user_id => &$extra_ref)
|
||||
{
|
||||
$extra_ref['rcmds_given'] = isset($rcmds_counts[$user_id]) ? 0 + $rcmds_counts[$user_id] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
# "Apply" only those fields which the consumer wanted.
|
||||
# "Apply" only those fields which the consumer wanted.
|
||||
|
||||
foreach (array('caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given') as $field)
|
||||
{
|
||||
if (!in_array($field, $fields))
|
||||
continue;
|
||||
foreach ($results as $uuid => &$result_ref)
|
||||
$result_ref[$field] = $extras[$uuid2id[$uuid]][$field];
|
||||
}
|
||||
}
|
||||
foreach (array('caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given') as $field)
|
||||
{
|
||||
if (!in_array($field, $fields))
|
||||
continue;
|
||||
foreach ($results as $uuid => &$result_ref)
|
||||
$result_ref[$field] = $extras[$uuid2id[$uuid]][$field];
|
||||
}
|
||||
}
|
||||
|
||||
# Check which user IDs were not found and mark them with null.
|
||||
# Check which user IDs were not found and mark them with null.
|
||||
|
||||
foreach ($user_uuids as $user_uuid)
|
||||
if (!isset($results[$user_uuid]))
|
||||
$results[$user_uuid] = null;
|
||||
foreach ($user_uuids as $user_uuid)
|
||||
if (!isset($results[$user_uuid]))
|
||||
$results[$user_uuid] = null;
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user