OKAPI Project update (r1031)
This commit is contained in:
@@ -23,75 +23,75 @@ require_once($GLOBALS['rootpath'].'okapi/urls.php');
|
|||||||
|
|
||||||
if (ob_list_handlers() == array('default output handler'))
|
if (ob_list_handlers() == array('default output handler'))
|
||||||
{
|
{
|
||||||
# We will assume that this one comes from "output_buffering" being turned on
|
# 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
|
# 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.
|
# pages. But we don't need it in OKAPI. We will just turn this off.
|
||||||
|
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class OkapiScriptEntryPointController
|
class OkapiScriptEntryPointController
|
||||||
{
|
{
|
||||||
public static function dispatch_request($uri)
|
public static function dispatch_request($uri)
|
||||||
{
|
{
|
||||||
# Chop off the ?args=... part.
|
# Chop off the ?args=... part.
|
||||||
|
|
||||||
if (strpos($uri, '?') !== false)
|
if (strpos($uri, '?') !== false)
|
||||||
$uri = substr($uri, 0, strpos($uri, '?'));
|
$uri = substr($uri, 0, strpos($uri, '?'));
|
||||||
|
|
||||||
# Chop off everything before "/okapi/". This should work for okay for most "weird"
|
# 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:
|
# server configurations. It will also address a more subtle issue described here:
|
||||||
# http://stackoverflow.com/questions/8040461/request-uri-unexpectedly-contains-fqdn
|
# http://stackoverflow.com/questions/8040461/request-uri-unexpectedly-contains-fqdn
|
||||||
|
|
||||||
if (strpos($uri, "/okapi/") !== false)
|
if (strpos($uri, "/okapi/") !== false)
|
||||||
$uri = substr($uri, strpos($uri, "/okapi/"));
|
$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)
|
if (strpos($uri, "/okapi/") !== 0)
|
||||||
throw new Exception("'$uri' is outside of the /okapi/ path.");
|
throw new Exception("'$uri' is outside of the /okapi/ path.");
|
||||||
$uri = substr($uri, 7);
|
$uri = substr($uri, 7);
|
||||||
|
|
||||||
# Initializing internals and running pre-request cronjobs (we don't want
|
# Initializing internals and running pre-request cronjobs (we don't want
|
||||||
# cronjobs to be run before "okapi/update", for example before database
|
# cronjobs to be run before "okapi/update", for example before database
|
||||||
# was installed).
|
# was installed).
|
||||||
|
|
||||||
$allow_cronjobs = ($uri != "update");
|
$allow_cronjobs = ($uri != "update");
|
||||||
Okapi::init_internals($allow_cronjobs);
|
Okapi::init_internals($allow_cronjobs);
|
||||||
|
|
||||||
# Checking for allowed patterns...
|
# Checking for allowed patterns...
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (OkapiUrls::$mapping as $pattern => $namespace)
|
foreach (OkapiUrls::$mapping as $pattern => $namespace)
|
||||||
{
|
{
|
||||||
$matches = null;
|
$matches = null;
|
||||||
if (preg_match("#$pattern#", $uri, $matches))
|
if (preg_match("#$pattern#", $uri, $matches))
|
||||||
{
|
{
|
||||||
# Pattern matched! Moving on to the proper View...
|
# Pattern matched! Moving on to the proper View...
|
||||||
|
|
||||||
array_shift($matches);
|
array_shift($matches);
|
||||||
require_once($GLOBALS['rootpath']."okapi/views/$namespace.php");
|
require_once($GLOBALS['rootpath']."okapi/views/$namespace.php");
|
||||||
$response = call_user_func_array(array('\\okapi\\views\\'.
|
$response = call_user_func_array(array('\\okapi\\views\\'.
|
||||||
str_replace('/', '\\', $namespace).'\\View', 'call'), $matches);
|
str_replace('/', '\\', $namespace).'\\View', 'call'), $matches);
|
||||||
if ($response)
|
if ($response)
|
||||||
$response->display();
|
$response->display();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Http404 $e)
|
catch (Http404 $e)
|
||||||
{
|
{
|
||||||
/* pass */
|
/* 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");
|
require_once($GLOBALS['rootpath']."okapi/views/http404.php");
|
||||||
$response = \okapi\views\http404\View::call();
|
$response = \okapi\views\http404\View::call();
|
||||||
$response->display();
|
$response->display();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Okapi::gettext_domain_init();
|
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
|
class OkapiDataStore extends OAuthDataStore
|
||||||
{
|
{
|
||||||
public function lookup_consumer($consumer_key)
|
public function lookup_consumer($consumer_key)
|
||||||
{
|
{
|
||||||
$row = Db::select_row("
|
$row = Db::select_row("
|
||||||
select `key`, secret, name, url, email, admin
|
select `key`, secret, name, url, email, admin
|
||||||
from okapi_consumers
|
from okapi_consumers
|
||||||
where `key` = '".mysql_real_escape_string($consumer_key)."'
|
where `key` = '".mysql_real_escape_string($consumer_key)."'
|
||||||
");
|
");
|
||||||
if (!$row)
|
if (!$row)
|
||||||
return null;
|
return null;
|
||||||
return new OkapiConsumer($row['key'], $row['secret'], $row['name'],
|
return new OkapiConsumer($row['key'], $row['secret'], $row['name'],
|
||||||
$row['url'], $row['email'], $row['admin'] ? true : false);
|
$row['url'], $row['email'], $row['admin'] ? true : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function lookup_token($consumer, $token_type, $token)
|
public function lookup_token($consumer, $token_type, $token)
|
||||||
{
|
{
|
||||||
$row = Db::select_row("
|
$row = Db::select_row("
|
||||||
select `key`, consumer_key, secret, token_type, user_id, verifier, callback
|
select `key`, consumer_key, secret, token_type, user_id, verifier, callback
|
||||||
from okapi_tokens
|
from okapi_tokens
|
||||||
where
|
where
|
||||||
consumer_key = '".mysql_real_escape_string($consumer->key)."'
|
consumer_key = '".mysql_real_escape_string($consumer->key)."'
|
||||||
and token_type = '".mysql_real_escape_string($token_type)."'
|
and token_type = '".mysql_real_escape_string($token_type)."'
|
||||||
and `key` = '".mysql_real_escape_string($token)."'
|
and `key` = '".mysql_real_escape_string($token)."'
|
||||||
");
|
");
|
||||||
if (!$row)
|
if (!$row)
|
||||||
return null;
|
return null;
|
||||||
switch ($row['token_type'])
|
switch ($row['token_type'])
|
||||||
{
|
{
|
||||||
case 'request':
|
case 'request':
|
||||||
return new OkapiRequestToken($row['key'], $row['secret'],
|
return new OkapiRequestToken($row['key'], $row['secret'],
|
||||||
$row['consumer_key'], $row['callback'], $row['user_id'],
|
$row['consumer_key'], $row['callback'], $row['user_id'],
|
||||||
$row['verifier']);
|
$row['verifier']);
|
||||||
case 'access':
|
case 'access':
|
||||||
return new OkapiAccessToken($row['key'], $row['secret'],
|
return new OkapiAccessToken($row['key'], $row['secret'],
|
||||||
$row['consumer_key'], $row['user_id']);
|
$row['consumer_key'], $row['user_id']);
|
||||||
default:
|
default:
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function lookup_nonce($consumer, $token, $nonce, $timestamp)
|
public function lookup_nonce($consumer, $token, $nonce, $timestamp)
|
||||||
{
|
{
|
||||||
# Since it's not important for us to save the actual token and nonce
|
# 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
|
# 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
|
# key in this hash and drop the column, but we will leave it be for
|
||||||
# now (for a couple of less important reasons).
|
# now (for a couple of less important reasons).
|
||||||
|
|
||||||
$nonce_hash = md5(serialize(array(
|
$nonce_hash = md5(serialize(array(
|
||||||
$token ? $token->key : null,
|
$token ? $token->key : null,
|
||||||
$timestamp,
|
$timestamp,
|
||||||
$nonce
|
$nonce
|
||||||
)));
|
)));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
# Time timestamp is saved separately, because we are periodically
|
# Time timestamp is saved separately, because we are periodically
|
||||||
# removing older nonces from the database (see cronjobs).
|
# removing older nonces from the database (see cronjobs).
|
||||||
|
|
||||||
Db::execute("
|
Db::execute("
|
||||||
insert into okapi_nonces (consumer_key, nonce_hash, timestamp)
|
insert into okapi_nonces (consumer_key, nonce_hash, timestamp)
|
||||||
values (
|
values (
|
||||||
'".mysql_real_escape_string($consumer->key)."',
|
'".mysql_real_escape_string($consumer->key)."',
|
||||||
'".mysql_real_escape_string($nonce_hash)."',
|
'".mysql_real_escape_string($nonce_hash)."',
|
||||||
'".mysql_real_escape_string($timestamp)."'
|
'".mysql_real_escape_string($timestamp)."'
|
||||||
);
|
);
|
||||||
");
|
");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch (\Exception $e)
|
catch (\Exception $e)
|
||||||
{
|
{
|
||||||
# INSERT failed. This nonce was already used.
|
# INSERT failed. This nonce was already used.
|
||||||
|
|
||||||
return $nonce;
|
return $nonce;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function new_request_token($consumer, $callback = null)
|
public function new_request_token($consumer, $callback = null)
|
||||||
{
|
{
|
||||||
if ((preg_match("#^[a-z][a-z0-9_.-]*://#", $callback) > 0) ||
|
if ((preg_match("#^[a-z][a-z0-9_.-]*://#", $callback) > 0) ||
|
||||||
$callback == "oob")
|
$callback == "oob")
|
||||||
{ /* ok */ }
|
{ /* ok */ }
|
||||||
else { throw new BadRequest("oauth_callback should begin with <scheme>://, or should equal 'oob'."); }
|
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),
|
$token = new OkapiRequestToken(Okapi::generate_key(20), Okapi::generate_key(40),
|
||||||
$consumer->key, $callback, null, Okapi::generate_key(8, true));
|
$consumer->key, $callback, null, Okapi::generate_key(8, true));
|
||||||
Db::execute("
|
Db::execute("
|
||||||
insert into okapi_tokens
|
insert into okapi_tokens
|
||||||
(`key`, secret, token_type, timestamp,
|
(`key`, secret, token_type, timestamp,
|
||||||
user_id, consumer_key, verifier, callback)
|
user_id, consumer_key, verifier, callback)
|
||||||
values (
|
values (
|
||||||
'".mysql_real_escape_string($token->key)."',
|
'".mysql_real_escape_string($token->key)."',
|
||||||
'".mysql_real_escape_string($token->secret)."',
|
'".mysql_real_escape_string($token->secret)."',
|
||||||
'request',
|
'request',
|
||||||
unix_timestamp(),
|
unix_timestamp(),
|
||||||
null,
|
null,
|
||||||
'".mysql_real_escape_string($consumer->key)."',
|
'".mysql_real_escape_string($consumer->key)."',
|
||||||
'".mysql_real_escape_string($token->verifier)."',
|
'".mysql_real_escape_string($token->verifier)."',
|
||||||
".(($token->callback_url == 'oob')
|
".(($token->callback_url == 'oob')
|
||||||
? "null"
|
? "null"
|
||||||
: "'".mysql_real_escape_string($token->callback_url)."'"
|
: "'".mysql_real_escape_string($token->callback_url)."'"
|
||||||
)."
|
)."
|
||||||
);
|
);
|
||||||
");
|
");
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function new_access_token($token, $consumer, $verifier = null)
|
public function new_access_token($token, $consumer, $verifier = null)
|
||||||
{
|
{
|
||||||
if ($token->consumer_key != $consumer->key)
|
if ($token->consumer_key != $consumer->key)
|
||||||
throw new BadRequest("Request Token given is not associated with the Consumer who signed the request.");
|
throw new BadRequest("Request Token given is not associated with the Consumer who signed the request.");
|
||||||
if (!$token->authorized_by_user_id)
|
if (!$token->authorized_by_user_id)
|
||||||
throw new BadRequest("Request Token given has not been authorized.");
|
throw new BadRequest("Request Token given has not been authorized.");
|
||||||
if ($token->verifier != $verifier)
|
if ($token->verifier != $verifier)
|
||||||
throw new BadRequest("Invalid verifier.");
|
throw new BadRequest("Invalid verifier.");
|
||||||
|
|
||||||
# Invalidate the Request Token.
|
# Invalidate the Request Token.
|
||||||
|
|
||||||
Db::execute("
|
Db::execute("
|
||||||
delete from okapi_tokens
|
delete from okapi_tokens
|
||||||
where `key` = '".mysql_real_escape_string($token->key)."'
|
where `key` = '".mysql_real_escape_string($token->key)."'
|
||||||
");
|
");
|
||||||
|
|
||||||
# In OKAPI, all Access Tokens are long lived. Therefore, we don't want
|
# 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
|
# 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)
|
# if there is already an Access Token generated for this (Consumer, User)
|
||||||
# pair and return it if there is.
|
# pair and return it if there is.
|
||||||
|
|
||||||
$row = Db::select_row("
|
$row = Db::select_row("
|
||||||
select `key`, secret
|
select `key`, secret
|
||||||
from okapi_tokens
|
from okapi_tokens
|
||||||
where
|
where
|
||||||
token_type = 'access'
|
token_type = 'access'
|
||||||
and user_id = '".mysql_real_escape_string($token->authorized_by_user_id)."'
|
and user_id = '".mysql_real_escape_string($token->authorized_by_user_id)."'
|
||||||
and consumer_key = '".mysql_real_escape_string($consumer->key)."'
|
and consumer_key = '".mysql_real_escape_string($consumer->key)."'
|
||||||
");
|
");
|
||||||
if ($row)
|
if ($row)
|
||||||
{
|
{
|
||||||
# Use existing Access Token
|
# Use existing Access Token
|
||||||
|
|
||||||
$access_token = new OkapiAccessToken($row['key'], $row['secret'],
|
$access_token = new OkapiAccessToken($row['key'], $row['secret'],
|
||||||
$consumer->key, $token->authorized_by_user_id);
|
$consumer->key, $token->authorized_by_user_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
# Generate a new Access Token.
|
# Generate a new Access Token.
|
||||||
|
|
||||||
$access_token = new OkapiAccessToken(Okapi::generate_key(20), Okapi::generate_key(40),
|
$access_token = new OkapiAccessToken(Okapi::generate_key(20), Okapi::generate_key(40),
|
||||||
$consumer->key, $token->authorized_by_user_id);
|
$consumer->key, $token->authorized_by_user_id);
|
||||||
Db::execute("
|
Db::execute("
|
||||||
insert into okapi_tokens
|
insert into okapi_tokens
|
||||||
(`key`, secret, token_type, timestamp, user_id, consumer_key)
|
(`key`, secret, token_type, timestamp, user_id, consumer_key)
|
||||||
values (
|
values (
|
||||||
'".mysql_real_escape_string($access_token->key)."',
|
'".mysql_real_escape_string($access_token->key)."',
|
||||||
'".mysql_real_escape_string($access_token->secret)."',
|
'".mysql_real_escape_string($access_token->secret)."',
|
||||||
'access',
|
'access',
|
||||||
unix_timestamp(),
|
unix_timestamp(),
|
||||||
'".mysql_real_escape_string($access_token->user_id)."',
|
'".mysql_real_escape_string($access_token->user_id)."',
|
||||||
'".mysql_real_escape_string($consumer->key)."'
|
'".mysql_real_escape_string($consumer->key)."'
|
||||||
);
|
);
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
return $access_token;
|
return $access_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function cleanup()
|
public function cleanup()
|
||||||
{
|
{
|
||||||
Db::execute("
|
Db::execute("
|
||||||
delete from okapi_nonces
|
delete from okapi_nonces
|
||||||
where
|
where
|
||||||
timestamp < unix_timestamp(date_add(now(), interval -6 minute))
|
timestamp < unix_timestamp(date_add(now(), interval -6 minute))
|
||||||
or timestamp > unix_timestamp(date_add(now(), interval 6 minute))
|
or timestamp > unix_timestamp(date_add(now(), interval 6 minute))
|
||||||
");
|
");
|
||||||
Db::execute("
|
Db::execute("
|
||||||
delete from okapi_tokens
|
delete from okapi_tokens
|
||||||
where
|
where
|
||||||
token_type = 'request'
|
token_type = 'request'
|
||||||
and timestamp < unix_timestamp(date_add(now(), interval -2 hour))
|
and timestamp < unix_timestamp(date_add(now(), interval -2 hour))
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ use okapi\OkapiServiceRunner;
|
|||||||
use okapi\OkapiInternalRequest;
|
use okapi\OkapiInternalRequest;
|
||||||
use okapi\OkapiFacadeConsumer;
|
use okapi\OkapiFacadeConsumer;
|
||||||
use okapi\OkapiFacadeAccessToken;
|
use okapi\OkapiFacadeAccessToken;
|
||||||
|
use okapi\Cache;
|
||||||
|
|
||||||
require_once($GLOBALS['rootpath']."okapi/core.php");
|
require_once($GLOBALS['rootpath']."okapi/core.php");
|
||||||
OkapiErrorHandler::$treat_notices_as_errors = true;
|
OkapiErrorHandler::$treat_notices_as_errors = true;
|
||||||
@@ -45,131 +46,214 @@ Okapi::init_internals();
|
|||||||
*/
|
*/
|
||||||
class Facade
|
class Facade
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Perform OKAPI service call, signed by internal 'facade' consumer key, and return the result
|
* 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
|
* (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
|
* 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).
|
* 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)
|
public static function service_call($service_name, $user_id_or_null, $parameters)
|
||||||
{
|
{
|
||||||
$request = new OkapiInternalRequest(
|
$request = new OkapiInternalRequest(
|
||||||
new OkapiFacadeConsumer(),
|
new OkapiFacadeConsumer(),
|
||||||
($user_id_or_null !== null) ? new OkapiFacadeAccessToken($user_id_or_null) : null,
|
($user_id_or_null !== null) ? new OkapiFacadeAccessToken($user_id_or_null) : null,
|
||||||
$parameters
|
$parameters
|
||||||
);
|
);
|
||||||
$request->perceive_as_http_request = true;
|
$request->perceive_as_http_request = true;
|
||||||
return OkapiServiceRunner::call($service_name, $request);
|
return OkapiServiceRunner::call($service_name, $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This works like service_call with two exceptions: 1. It passes all your
|
* 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
|
* current HTTP request headers to OKAPI (which can make use of them in
|
||||||
* terms of caching), 2. It outputs the service response directly, instead
|
* terms of caching), 2. It outputs the service response directly, instead
|
||||||
* of returning it.
|
* of returning it.
|
||||||
*/
|
*/
|
||||||
public static function service_display($service_name, $user_id_or_null, $parameters)
|
public static function service_display($service_name, $user_id_or_null, $parameters)
|
||||||
{
|
{
|
||||||
$request = new OkapiInternalRequest(
|
$request = new OkapiInternalRequest(
|
||||||
new OkapiFacadeConsumer(),
|
new OkapiFacadeConsumer(),
|
||||||
($user_id_or_null !== null) ? new OkapiFacadeAccessToken($user_id_or_null) : null,
|
($user_id_or_null !== null) ? new OkapiFacadeAccessToken($user_id_or_null) : null,
|
||||||
$parameters
|
$parameters
|
||||||
);
|
);
|
||||||
$request->perceive_as_http_request = true;
|
$request->perceive_as_http_request = true;
|
||||||
if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
|
if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
|
||||||
$request->etag = $_SERVER['HTTP_IF_NONE_MATCH'];
|
$request->etag = $_SERVER['HTTP_IF_NONE_MATCH'];
|
||||||
$response = OkapiServiceRunner::call($service_name, $request);
|
$response = OkapiServiceRunner::call($service_name, $request);
|
||||||
$response->display();
|
$response->display();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a search set from a temporary table. This is very similar to
|
* Create a search set from a temporary table. This is very similar to
|
||||||
* the "services/caches/search/save" method, but allows OC server to
|
* the "services/caches/search/save" method, but allows OC server to
|
||||||
* include its own result instead of using OKAPI's search options. The
|
* 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
|
* $temp_table should be a valid name of a temporary table with the
|
||||||
* following (or similar) structure:
|
* following (or similar) structure:
|
||||||
*
|
*
|
||||||
* create temporary table temp_12345 (
|
* create temporary table temp_12345 (
|
||||||
* cache_id integer primary key
|
* cache_id integer primary key
|
||||||
* ) engine=memory;
|
* ) engine=memory;
|
||||||
*/
|
*/
|
||||||
public static function import_search_set($temp_table, $min_store, $max_ref_age)
|
public static function import_search_set($temp_table, $min_store, $max_ref_age)
|
||||||
{
|
{
|
||||||
require_once 'services/caches/search/save.php';
|
require_once($GLOBALS['rootpath'].'okapi/services/caches/search/save.php');
|
||||||
$tables = array('caches', $temp_table);
|
$tables = array('caches', $temp_table);
|
||||||
$where_conds = array(
|
$where_conds = array(
|
||||||
$temp_table.".cache_id = caches.cache_id",
|
$temp_table.".cache_id = caches.cache_id",
|
||||||
'caches.status in (1,2,3)',
|
'caches.status in (1,2,3)',
|
||||||
);
|
);
|
||||||
return \okapi\services\caches\search\save\WebService::get_set(
|
return \okapi\services\caches\search\save\WebService::get_set(
|
||||||
$tables, $where_conds, $min_store, $max_ref_age
|
$tables, $where_conds, $min_store, $max_ref_age
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark the specified caches as *possibly* modified. The replicate module
|
* Mark the specified caches as *possibly* modified. The replicate module
|
||||||
* will scan for changes within these caches on the next changelog update.
|
* will scan for changes within these caches on the next changelog update.
|
||||||
* This is useful in some cases, when OKAPI cannot detect the modification
|
* This is useful in some cases, when OKAPI cannot detect the modification
|
||||||
* for itself (grep OCPL code for examples). See issue #179.
|
* for itself (grep OCPL code for examples). See issue #179.
|
||||||
*
|
*
|
||||||
* $cache_codes - a single cache code OR an array of cache codes.
|
* $cache_codes - a single cache code OR an array of cache codes.
|
||||||
*/
|
*/
|
||||||
public static function schedule_geocache_check($cache_codes)
|
public static function schedule_geocache_check($cache_codes)
|
||||||
{
|
{
|
||||||
if (!is_array($cache_codes))
|
if (!is_array($cache_codes))
|
||||||
$cache_codes = array($cache_codes);
|
$cache_codes = array($cache_codes);
|
||||||
Db::execute("
|
Db::execute("
|
||||||
update caches
|
update caches
|
||||||
set okapi_syncbase = now()
|
set okapi_syncbase = now()
|
||||||
where wp_oc in ('".implode("','", array_map('mysql_real_escape_string', $cache_codes))."')
|
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
|
* Find all log entries of the specified user for the specified cache and
|
||||||
* mark them as *possibly* modified. See issue #265.
|
* mark them as *possibly* modified. See issue #265.
|
||||||
*
|
*
|
||||||
* $cache_id - internal ID of the geocache,
|
* $cache_id - internal ID of the geocache,
|
||||||
* $user_id - internal ID of the user.
|
* $user_id - internal ID of the user.
|
||||||
*/
|
*/
|
||||||
public static function schedule_user_entries_check($cache_id, $user_id)
|
public static function schedule_user_entries_check($cache_id, $user_id)
|
||||||
{
|
{
|
||||||
Db::execute("
|
Db::execute("
|
||||||
update cache_logs
|
update cache_logs
|
||||||
set okapi_syncbase = now()
|
set okapi_syncbase = now()
|
||||||
where
|
where
|
||||||
cache_id = '".mysql_real_escape_string($cache_id)."'
|
cache_id = '".mysql_real_escape_string($cache_id)."'
|
||||||
and user_id = '".mysql_real_escape_string($user_id)."'
|
and user_id = '".mysql_real_escape_string($user_id)."'
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run OKAPI database update.
|
* Run OKAPI database update.
|
||||||
* Will output messages to stdout.
|
* Will output messages to stdout.
|
||||||
*/
|
*/
|
||||||
public static function database_update()
|
public static function database_update()
|
||||||
{
|
{
|
||||||
require_once($GLOBALS['rootpath']."okapi/views/update.php");
|
require_once($GLOBALS['rootpath']."okapi/views/update.php");
|
||||||
$update = new views\update\View;
|
$update = new views\update\View;
|
||||||
$update->call();
|
$update->call();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You will probably want to call that with FALSE when using Facade
|
* You will probably want to call that with FALSE when using Facade
|
||||||
* in buggy, legacy OC code. This will disable OKAPI's default behavior
|
* in buggy, legacy OC code. This will disable OKAPI's default behavior
|
||||||
* of treating NOTICEs as errors.
|
* of treating NOTICEs as errors.
|
||||||
*/
|
*/
|
||||||
public static function disable_error_handling()
|
public static function disable_error_handling()
|
||||||
{
|
{
|
||||||
OkapiErrorHandler::disable();
|
OkapiErrorHandler::disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If you disabled OKAPI's error handling with disable_error_handling,
|
* If you disabled OKAPI's error handling with disable_error_handling,
|
||||||
* you may reenable it with this method.
|
* you may reenable it with this method.
|
||||||
*/
|
*/
|
||||||
public static function reenable_error_handling()
|
public static function reenable_error_handling()
|
||||||
{
|
{
|
||||||
OkapiErrorHandler::reenable();
|
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
|
class OCSession
|
||||||
{
|
{
|
||||||
/** Return ID of currently logged in user or NULL if no user is logged in. */
|
/** Return ID of currently logged in user or NULL if no user is logged in. */
|
||||||
public static function get_user_id()
|
public static function get_user_id()
|
||||||
{
|
{
|
||||||
static $cached_result = false;
|
static $cached_result = false;
|
||||||
if ($cached_result !== false)
|
if ($cached_result !== false)
|
||||||
return $cached_result;
|
return $cached_result;
|
||||||
|
|
||||||
$cookie_name = Settings::get('OC_COOKIE_NAME');
|
$cookie_name = Settings::get('OC_COOKIE_NAME');
|
||||||
if (!isset($_COOKIE[$cookie_name]))
|
if (!isset($_COOKIE[$cookie_name]))
|
||||||
return null;
|
return null;
|
||||||
$OC_data = unserialize(base64_decode($_COOKIE[$cookie_name]));
|
$OC_data = unserialize(base64_decode($_COOKIE[$cookie_name]));
|
||||||
if (!isset($OC_data['sessionid']))
|
if (!isset($OC_data['sessionid']))
|
||||||
return null;
|
return null;
|
||||||
$OC_sessionid = $OC_data['sessionid'];
|
$OC_sessionid = $OC_data['sessionid'];
|
||||||
if (!$OC_sessionid)
|
if (!$OC_sessionid)
|
||||||
return null;
|
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 ""
|
msgstr ""
|
||||||
"Project-Id-Version: OKAPI\n"
|
"Project-Id-Version: OKAPI\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2013-07-10 12:30+0100\n"
|
"POT-Creation-Date: 2014-01-23 15:51+0100\n"
|
||||||
"PO-Revision-Date: 2013-07-10 12:31+0100\n"
|
"PO-Revision-Date: 2014-01-23 15:52+0100\n"
|
||||||
"Last-Translator: following <following@online.de>\n"
|
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
||||||
"Language-Team: following <following@online.de>\n"
|
"Language-Team: following <following@online.de>\n"
|
||||||
"Language: German\n"
|
"Language: de\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -14,20 +14,29 @@ msgstr ""
|
|||||||
"X-Poedit-Basepath: .\n"
|
"X-Poedit-Basepath: .\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Poedit-SourceCharset: UTF-8\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-0: c:\\source\\oc\\server-3.0\\htdocs\\okapi\n"
|
||||||
"X-Poedit-SearchPath-1: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api"
|
"X-Poedit-SearchPath-1: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api"
|
||||||
"\\okapi\n"
|
"\\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"
|
msgid "Stage"
|
||||||
msgstr "Station"
|
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"
|
msgid "National Park / Landscape"
|
||||||
msgstr "Nationalpark / Landschaft"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||||
@@ -35,7 +44,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Diese <a href='%s'>Cache</a>-Beschreibung stammt von <a href='%s'>%s</a>."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
"© <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; "
|
"creativecommons.org/licenses/by-nc-nd/3.0/de/'>CC-BY-NC-ND</a>, Stand: %s; "
|
||||||
"alle Logeinträge © jeweiliger Autor"
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
"© <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 "
|
"creativecommons.org/licenses/by-nc-nd/3.0/de/'>CC-BY-NC-ND</a>; alle "
|
||||||
"Logeinträge © jeweiliger Autor"
|
"Logeinträge © jeweiliger Autor"
|
||||||
|
|
||||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:31
|
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:360
|
||||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:60
|
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"
|
msgid "hidden by"
|
||||||
msgstr "versteckt von"
|
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
|
#, php-format
|
||||||
msgid "%d recommendation"
|
msgid "%d recommendation"
|
||||||
msgid_plural "%d recommendations"
|
msgid_plural "%d recommendations"
|
||||||
msgstr[0] "%d Empfehlung"
|
msgstr[0] "%d Empfehlung"
|
||||||
msgstr[1] "%d Empfehlungen"
|
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
|
#, php-format
|
||||||
msgid "found %d time"
|
msgid "found %d time"
|
||||||
msgid_plural "found %d times"
|
msgid_plural "found %d times"
|
||||||
msgstr[0] "%d mal gefunden"
|
msgstr[0] "%d mal gefunden"
|
||||||
msgstr[1] "%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
|
#, php-format
|
||||||
msgid "%d trackable"
|
msgid "%d trackable"
|
||||||
msgid_plural "%d trackables"
|
msgid_plural "%d trackables"
|
||||||
msgstr[0] "%d Geokret"
|
msgstr[0] "%d Geokret"
|
||||||
msgstr[1] "%d Geokrets"
|
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"
|
msgid "Personal notes"
|
||||||
msgstr "Persönliche Notizen"
|
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"
|
msgid "Attributes"
|
||||||
msgstr "Attribute"
|
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"
|
msgid "Trackables"
|
||||||
msgstr "Geokrets"
|
msgstr "Geokrets"
|
||||||
|
|
||||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:88
|
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:90
|
||||||
#: 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:106
|
||||||
msgid "Images"
|
msgid "Images"
|
||||||
msgstr "Bilder"
|
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"
|
msgid "Spoilers"
|
||||||
msgstr "Spoiler"
|
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"
|
msgid "Image descriptions"
|
||||||
msgstr "Bildbeschreibungen"
|
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:"
|
msgid "The cache probably is located in the following protection areas:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Der Geocache befindet sich wahrscheinlich in den folgenden Schutzgebieten:"
|
"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 ""
|
msgid ""
|
||||||
"You are trying to publish a log entry with a date in future. Cache log "
|
"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."
|
"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 "
|
"Das Datum deines Logeintrags liegt in der Zukunft. Cache-Logs können nur für "
|
||||||
"die Vergangenheit oder für heute eingetragen werden."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"However, your cache rating was ignored, because %s does not have a rating "
|
"However, your cache rating was ignored, because %s does not have a rating "
|
||||||
@@ -129,7 +159,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Deine Cachewertung wurde jedoch ignoriert, weil %s kein Bewertungssystem hat."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"However, your cache recommendation was ignored, because %s does not allow "
|
"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 "
|
"Deine Empfehlung wurde jedoch ignoriert, weil auf %s keine Event-Caches "
|
||||||
"empfohlen werden können."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
"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 "
|
"Deine Angabe \"benötigt Wartung\" wurde jedoch ignoriert, weil es diese "
|
||||||
"Funktion bei %s nicht gibt."
|
"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 ""
|
msgid ""
|
||||||
"This cache is an Event cache. You cannot \"Find\" it (but you can attend it, "
|
"This cache is an Event cache. You cannot \"Find\" it (but you can attend it, "
|
||||||
"or comment on it)!"
|
"or comment on it)!"
|
||||||
@@ -155,7 +185,7 @@ msgstr ""
|
|||||||
"Dies ist ein Event-Cache. Du kannst ihn nicht \"finden\" (aber du kannst am "
|
"Dies ist ein Event-Cache. Du kannst ihn nicht \"finden\" (aber du kannst am "
|
||||||
"Event teilnehmen oder einen Hinweis loggen)."
|
"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 ""
|
msgid ""
|
||||||
"This cache is NOT an Event cache. You cannot \"Attend\" it (but you can find "
|
"This cache is NOT an Event cache. You cannot \"Attend\" it (but you can find "
|
||||||
"it, or comment on it)!"
|
"it, or comment on it)!"
|
||||||
@@ -163,26 +193,26 @@ msgstr ""
|
|||||||
"Dies ist KEIN Event-Cache. Du kannst an ihm nicht \"teilnehmen\" (aber du "
|
"Dies ist KEIN Event-Cache. Du kannst an ihm nicht \"teilnehmen\" (aber du "
|
||||||
"kannst ihn finden oder kommentieren)."
|
"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."
|
msgid "Your have to supply some text for your comment."
|
||||||
msgstr "Du musst einen Text für dein Hinweislog eingeben!"
|
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!"
|
msgid "This cache requires a password. You didn't provide one!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Dieser Cache kann nur mit Kennwort geloggt werden, aber du hast keines "
|
"Dieser Cache kann nur mit Kennwort geloggt werden, aber du hast keines "
|
||||||
"angegeben."
|
"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!"
|
msgid "Invalid password!"
|
||||||
msgstr "Ungültiges Kennwort!"
|
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."
|
msgid "You have already submitted a log entry with exactly the same contents."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Du hast bereits einen Logeintrag mit genau dem gleichen Inhalt gemacht."
|
"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 ""
|
msgid ""
|
||||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||||
"\"Comments\" only!"
|
"\"Comments\" only!"
|
||||||
@@ -190,53 +220,53 @@ msgstr ""
|
|||||||
"Du hast diesen Cache bereits als gefunden geloggt. Ein zweites Fundlog ist "
|
"Du hast diesen Cache bereits als gefunden geloggt. Ein zweites Fundlog ist "
|
||||||
"nicht möglich, aber du kannst stattdessen einen Hinweis loggen."
|
"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!"
|
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Als Besitzer des Caches kannst du nur Hinweise loggen, keine Funde oder "
|
"Als Besitzer des Caches kannst du nur Hinweise loggen, keine Funde oder "
|
||||||
"Nichtfunde."
|
"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."
|
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Du hast diesen Cache bereits bewertet. Deine Bewertung ist nicht änderbar."
|
"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."
|
msgid "You have already recommended this cache once."
|
||||||
msgstr "Du hast diesen Cache bereits empfohlen."
|
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!"
|
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Du musst mehr Caches finden, um eine weitere Bewertung abgeben zu können!"
|
"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\"."
|
msgid "Event caches cannot \"need maintenance\"."
|
||||||
msgstr "Event-Caches können keine \"Wartung benötigen\"."
|
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."
|
msgid "Your cache log entry was posted successfully."
|
||||||
msgstr "Dein Log wurde veröffentlicht."
|
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"
|
msgid "Authorization Form"
|
||||||
msgstr "Authorisierungs-Formular"
|
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"
|
msgid "Expired request"
|
||||||
msgstr "Anfrage abgelaufen"
|
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."
|
msgid "Unfortunately, the request has expired. Please try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Die Anfrage ist wegen Zeitüberschreitung abgelaufen. Bitte versuche es noch "
|
"Die Anfrage ist wegen Zeitüberschreitung abgelaufen. Bitte versuche es noch "
|
||||||
"einmal."
|
"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..."
|
msgid "External application is requesting access..."
|
||||||
msgstr "Eine externe Anwendung wünscht Zugriff ..."
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<b>%s</b> wants to access your <b>%s</b> account. Do you agree to grant "
|
"<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 "
|
"<b>%s</b> möchte auf dein <b>%s</b>-Benutzerkonto zugreifen. Möchtest du "
|
||||||
"dieser Anwendung Zugriff gewähren?"
|
"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"
|
msgid "I agree"
|
||||||
msgstr "Ja"
|
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"
|
msgid "Decline"
|
||||||
msgstr "Nein"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
" <p>Once permission is granted it is valid until its "
|
||||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
"withdrawal on\n"
|
||||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
" the <a href='%s'>applications management</a> page.</p>\n"
|
||||||
"OKAPI Framework</a>.\n"
|
" <p>The application will access your acount via <a "
|
||||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
"href='%s'>the OKAPI Framework</a>.\n"
|
||||||
"methods delivered\n"
|
" If you allow this request application will be able to "
|
||||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
"access all methods delivered\n"
|
||||||
"name.\n"
|
" by the OKAPI Framework, i.e. post log entries on "
|
||||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
"geocaches in your name.\n"
|
||||||
"\t\t\t\t"
|
" You can revoke this permission at any moment.</p>\n"
|
||||||
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Wenn die Erlaubnis erteilt wurde, ist sie so lange gültig, bis "
|
"\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\tDu kannst diese Erlaubnis jederzeit widerrufen.</p>\n"
|
||||||
"\t\t\t\t"
|
"\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"
|
msgid "Authorization Succeeded"
|
||||||
msgstr "Authorisierung erfolgreich"
|
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"
|
msgid "Access successfully granted"
|
||||||
msgstr "Zugang wurde gewährt"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
" <p><b>You've just granted %s application access to your %s "
|
||||||
"b>\n"
|
"account.</b>\n"
|
||||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
" To complete the operation, go back to %s and enter the "
|
||||||
"code:</p>\n"
|
"following PIN code:</p>\n"
|
||||||
"\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t<p><b>Du hast der Anwendung \"%s\" Zugriff auf dein %s-Benutzerkonto "
|
"\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"
|
"PIN-Code ein:</p>\n"
|
||||||
"\t\t\t"
|
"\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"
|
msgid "My Apps"
|
||||||
msgstr "Meine 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"
|
msgid "Your external applications"
|
||||||
msgstr "Deine externen Anwendungen"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
" <p>This is the list of applications which you granted "
|
||||||
"your <b>%s</b> account.\n"
|
"access to your <b>%s</b> account.\n"
|
||||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
" This page gives you the abbility to revoke all "
|
||||||
"privileges.\n"
|
"previously granted privileges.\n"
|
||||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
" Once you click \"remove\" the application will no longer "
|
||||||
"to perform any\n"
|
"be able to perform any\n"
|
||||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
" actions on your behalf.</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Dies ist eine Liste der Anwendungen, denen du Zugriff auf dein "
|
"\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"
|
"Aktionen mehr unter deinem \t\t\t\t\tBenutzername ausführen können.</p>\n"
|
||||||
"\t\t\t\t"
|
"\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"
|
msgid "remove"
|
||||||
msgstr "entfernen"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
" <p>Thanks to the <a href='%s'>OKAPI Framework</a> you "
|
||||||
"external applications\n"
|
"can grant external applications\n"
|
||||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
" access to your <b>%s</b> account. Currently no "
|
||||||
"authorized to act\n"
|
"applications are authorized to act\n"
|
||||||
"\t\t\t\t\ton your behalf. Once you start using external Opencaching "
|
" on your behalf. Once you start using external "
|
||||||
"applications, they will appear here.</p>\n"
|
"Opencaching applications, they will appear here.</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Die <a href='%s'>OKAPI-Schnittstelle</a> ermöglichst es dir, "
|
"\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 ""
|
msgstr ""
|
||||||
"Project-Id-Version: OKAPI\n"
|
"Project-Id-Version: OKAPI\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2013-07-19 08:41+0100\n"
|
"POT-Creation-Date: 2014-01-23 15:53+0100\n"
|
||||||
"PO-Revision-Date: 2013-07-19 08:46+0100\n"
|
"PO-Revision-Date: 2014-01-23 16:04+0100\n"
|
||||||
"Last-Translator: faina09 <stefanocotterli@gmail.com>\n"
|
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
||||||
"Language-Team: following <following@online.de>\n"
|
"Language-Team: following <following@online.de>\n"
|
||||||
"Language: Italian\n"
|
"Language: it\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -14,22 +14,31 @@ msgstr ""
|
|||||||
"X-Poedit-Basepath: .\n"
|
"X-Poedit-Basepath: .\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Poedit-SourceCharset: UTF-8\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-0: c:\\source\\okapi\\following2\n"
|
||||||
"X-Poedit-SearchPath-1: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api"
|
"X-Poedit-SearchPath-1: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api"
|
||||||
"\\okapi\n"
|
"\\okapi\n"
|
||||||
"X-Poedit-SearchPath-2: C:\\Users\\stefano.cotterli\\Desktop\\opencaching-"
|
"X-Poedit-SearchPath-2: C:\\Users\\stefano.cotterli\\Desktop\\opencaching-"
|
||||||
"api\n"
|
"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"
|
msgid "Stage"
|
||||||
msgstr "Passo"
|
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"
|
msgid "National Park / Landscape"
|
||||||
msgstr "Parco Nazionale / Paesaggio"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
"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 "
|
"La deescrizione di questa <a href='%s'>geocache</a>proviene dal sito <a "
|
||||||
"href='%s'>%s</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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||||
@@ -46,7 +55,7 @@ msgid ""
|
|||||||
"%s; all log entries © their authors"
|
"%s; all log entries © their authors"
|
||||||
msgstr ""
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||||
@@ -54,62 +63,83 @@ msgid ""
|
|||||||
"log entries © their authors"
|
"log entries © their authors"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:31
|
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpx.php:360
|
||||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:60
|
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"
|
msgid "hidden by"
|
||||||
msgstr "nascosta da"
|
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
|
#, php-format
|
||||||
msgid "%d recommendation"
|
msgid "%d recommendation"
|
||||||
msgid_plural "%d recommendations"
|
msgid_plural "%d recommendations"
|
||||||
msgstr[0] "%d raccomandazione"
|
msgstr[0] "%d raccomandazione"
|
||||||
msgstr[1] "%d raccomandazioni"
|
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
|
#, php-format
|
||||||
msgid "found %d time"
|
msgid "found %d time"
|
||||||
msgid_plural "found %d times"
|
msgid_plural "found %d times"
|
||||||
msgstr[0] "trovata %d volta"
|
msgstr[0] "trovata %d volta"
|
||||||
msgstr[1] "trovata %d volte"
|
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
|
#, php-format
|
||||||
msgid "%d trackable"
|
msgid "%d trackable"
|
||||||
msgid_plural "%d trackables"
|
msgid_plural "%d trackables"
|
||||||
msgstr[0] "%d travel bug"
|
msgstr[0] "%d travel bug"
|
||||||
msgstr[1] "%d travel bugs"
|
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"
|
msgid "Personal notes"
|
||||||
msgstr "Note personali"
|
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"
|
msgid "Attributes"
|
||||||
msgstr "Attributi"
|
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"
|
msgid "Trackables"
|
||||||
msgstr "Travel bugs"
|
msgstr "Travel bugs"
|
||||||
|
|
||||||
#: C:\Users\stefano.cotterli\Desktop\opencaching-api/okapi/services/caches/formatters/gpxfile.tpl.php:88
|
#: D:\PRIV\Projekty\EclipseWorkspace\opencaching-api\okapi/services/caches/formatters/gpxfile.tpl.php:90
|
||||||
#: 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:106
|
||||||
msgid "Images"
|
msgid "Images"
|
||||||
msgstr "Immagini"
|
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"
|
msgid "Spoilers"
|
||||||
msgstr "Spoiler"
|
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"
|
msgid "Image descriptions"
|
||||||
msgstr "Descrizione immagine"
|
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:"
|
msgid "The cache probably is located in the following protection areas:"
|
||||||
msgstr "La cache probabilmente è situata nelle seguenti aree protette:"
|
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 ""
|
msgid ""
|
||||||
"You are trying to publish a log entry with a date in future. Cache log "
|
"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."
|
"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 "
|
"Hai cercato di pubblicare un log con una data nel futuro. E' permsso loggare "
|
||||||
"una cache con una data passata, ma NON futura."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"However, your cache rating was ignored, because %s does not have a rating "
|
"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 "
|
"Tuttavia, la tua valutazione della cache sarà ignorata, perché %s non ha un "
|
||||||
"sistema di valutazione."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"However, your cache recommendation was ignored, because %s does not allow "
|
"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 "
|
"Tuttavia, la tua valutazione della cache sarà ignorata, perché %s non ha "
|
||||||
"permette la valutazione di cache evento."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
"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, "
|
"Tuttavia, la tua segnalazione di \"manutenzione necessaria\" sarà ignorata, "
|
||||||
"perché %s non supporta questa opzione."
|
"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 ""
|
msgid ""
|
||||||
"This cache is an Event cache. You cannot \"Find\" it (but you can attend it, "
|
"This cache is an Event cache. You cannot \"Find\" it (but you can attend it, "
|
||||||
"or comment on it)!"
|
"or comment on it)!"
|
||||||
@@ -152,7 +182,7 @@ msgstr ""
|
|||||||
"Questa cache è una cache Evento. Non puoi \"Trovarla\" (ma puoi partecipare, "
|
"Questa cache è una cache Evento. Non puoi \"Trovarla\" (ma puoi partecipare, "
|
||||||
"o commentare l'evento)!"
|
"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 ""
|
msgid ""
|
||||||
"This cache is NOT an Event cache. You cannot \"Attend\" it (but you can find "
|
"This cache is NOT an Event cache. You cannot \"Attend\" it (but you can find "
|
||||||
"it, or comment on it)!"
|
"it, or comment on it)!"
|
||||||
@@ -160,23 +190,23 @@ msgstr ""
|
|||||||
"Questa cache NON è una cache Evento. Non puoi \"Partecipare\" (ma puoi "
|
"Questa cache NON è una cache Evento. Non puoi \"Partecipare\" (ma puoi "
|
||||||
"trovarla, o inserirci un commento)!"
|
"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."
|
msgid "Your have to supply some text for your comment."
|
||||||
msgstr "Devi inserire del testo per il tuo commento."
|
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!"
|
msgid "This cache requires a password. You didn't provide one!"
|
||||||
msgstr "Questa cache richiede una password, ma non ne hai fornita nessuuna."
|
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!"
|
msgid "Invalid password!"
|
||||||
msgstr "Password non valida!"
|
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."
|
msgid "You have already submitted a log entry with exactly the same contents."
|
||||||
msgstr "Hai già inserito un log esattamente con lo stesso contenuto."
|
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 ""
|
msgid ""
|
||||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||||
"\"Comments\" only!"
|
"\"Comments\" only!"
|
||||||
@@ -184,49 +214,49 @@ msgstr ""
|
|||||||
"Hai già inserito un log \"Trovata\". Adesso puoi inserire solamente "
|
"Hai già inserito un log \"Trovata\". Adesso puoi inserire solamente "
|
||||||
"\"Commenti\"!"
|
"\"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!"
|
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||||
msgstr "Sei il proprietario della cache. Puoi inserire solamente \"Commenti\"!"
|
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."
|
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Hai giàvalutato questa cache. La tua valutazione non può essere cambiata."
|
"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."
|
msgid "You have already recommended this cache once."
|
||||||
msgstr "Hai già raccmandato questa cache."
|
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!"
|
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Non hai possibilità di dare raccomandazioni. Prima devio trovare altre cache!"
|
"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\"."
|
msgid "Event caches cannot \"need maintenance\"."
|
||||||
msgstr "Le cache evento non necessitano di manutenzione!"
|
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."
|
msgid "Your cache log entry was posted successfully."
|
||||||
msgstr "Il tuo log sulla cache è stato correttamente inserito."
|
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"
|
msgid "Authorization Form"
|
||||||
msgstr "Modulo di autorizzazione"
|
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"
|
msgid "Expired request"
|
||||||
msgstr "Richiesta scaduta"
|
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."
|
msgid "Unfortunately, the request has expired. Please try again."
|
||||||
msgstr "Sfortunatamente, la richiesta è scaduta. Per favore riprova."
|
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..."
|
msgid "External application is requesting access..."
|
||||||
msgstr "Una applicazione esterna sta richiedendo l'accesso."
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<b>%s</b> wants to access your <b>%s</b> account. Do you agree to grant "
|
"<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 "
|
"<b>%s</b> vuole accedere al tuo account <b>%s</b>. Sei d'accordo nel "
|
||||||
"concedere l'accesso a questa applicazione?"
|
"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"
|
msgid "I agree"
|
||||||
msgstr "Sono d'accordo"
|
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"
|
msgid "Decline"
|
||||||
msgstr "No"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
" <p>Once permission is granted it is valid until its "
|
||||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
"withdrawal on\n"
|
||||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
" the <a href='%s'>applications management</a> page.</p>\n"
|
||||||
"OKAPI Framework</a>.\n"
|
" <p>The application will access your acount via <a "
|
||||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
"href='%s'>the OKAPI Framework</a>.\n"
|
||||||
"methods delivered\n"
|
" If you allow this request application will be able to "
|
||||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
"access all methods delivered\n"
|
||||||
"name.\n"
|
" by the OKAPI Framework, i.e. post log entries on "
|
||||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
"geocaches in your name.\n"
|
||||||
"\t\t\t\t"
|
" You can revoke this permission at any moment.</p>\n"
|
||||||
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Una volta concessa, l'autorizzazoine è valida finché non venga\n"
|
"<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>.</"
|
"revocata nella pagina di <a href='%s'>gestione applicazioni</a>.</p>\n"
|
||||||
"p>\n"
|
"<p>L'applicazione accederà al tuo account tramite il <a href='%s'>frameword "
|
||||||
"\t\t\t\t\t<p>L'applicazione accederà al tuo account tramite il <a "
|
"OKAPI</a>.\n"
|
||||||
"href='%s'>frameword OKAPI</a>.\n"
|
"Se permetti questa richiesta, l'applicazione potrà accedere a tutti i metodi "
|
||||||
"\t\t\t\t\tSe permetti questa richiesta, l'applicazione potrà accedere a "
|
"forniti\n"
|
||||||
"tutti i metodi forniti\n"
|
"dal framework OKAPI, per es. postare i log delle geocache a tuo nome..\n"
|
||||||
"\t\t\t\t\tdal framework OKAPI, per es. postare i log delle geocache a tuo "
|
"Puoi revocare questo permesso in qualsiasi momento.</p>"
|
||||||
"nome..\n"
|
|
||||||
"\t\t\t\t\tPuoi revocare questo permesso in qualsiasi momento.</p>\n"
|
|
||||||
"\t\t\t\t"
|
|
||||||
|
|
||||||
#: 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"
|
msgid "Authorization Succeeded"
|
||||||
msgstr "Autorizzazione concessa"
|
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"
|
msgid "Access successfully granted"
|
||||||
msgstr "Accesso correttamente consentito"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
" <p><b>You've just granted %s application access to your %s "
|
||||||
"b>\n"
|
"account.</b>\n"
|
||||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
" To complete the operation, go back to %s and enter the "
|
||||||
"code:</p>\n"
|
"following PIN code:</p>\n"
|
||||||
"\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t<p><b>Hai appena concesso all'applicazione \"%s\" l'accesso al tuo "
|
"<p><b>Hai appena concesso all'applicazione \"%s\" l'accesso al tuo account "
|
||||||
"account %s.</b>\n"
|
"%s.</b>\n"
|
||||||
"\t\t\t\tPer completare l'operazione, riorna a %s e inserisci il seguente "
|
"Per completare l'operazione, riorna a %s e inserisci il seguente codice PIN:"
|
||||||
"codice PIN:</p>\n"
|
"</p>"
|
||||||
"\t\t\t"
|
|
||||||
|
|
||||||
#: 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"
|
msgid "My Apps"
|
||||||
msgstr "Mie App"
|
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"
|
msgid "Your external applications"
|
||||||
msgstr "Le tue applicazioni esterne"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
" <p>This is the list of applications which you granted "
|
||||||
"your <b>%s</b> account.\n"
|
"access to your <b>%s</b> account.\n"
|
||||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
" This page gives you the abbility to revoke all "
|
||||||
"privileges.\n"
|
"previously granted privileges.\n"
|
||||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
" Once you click \"remove\" the application will no longer "
|
||||||
"to perform any\n"
|
"be able to perform any\n"
|
||||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
" actions on your behalf.</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Questa è la lista delle applicazioni a cui hai concesso "
|
"<p>Questa è la lista delle applicazioni a cui hai concesso l'accesso al tuo "
|
||||||
"l'accesso al tuo account <b>%s</b.\n"
|
"account <b>%s</b.\n"
|
||||||
"\t\t\t\t\tQuesta pagina ti da la possibilità di revocare tutti privilegi "
|
"Questa pagina ti da la possibilità di revocare tutti privilegi "
|
||||||
"precedentemente concessi.\n"
|
"precedentemente concessi.\n"
|
||||||
"\t\t\t\t\tQundo clicchi su \"rimuovi\" all'applicazione non sarà più "
|
"Qundo clicchi su \"rimuovi\" all'applicazione non sarà più concesso eseguire "
|
||||||
"concesso eseguire nessuna\n"
|
"nessuna\n"
|
||||||
" \t\t\t\t\tazione per tuo conto.</p>\n"
|
"azione per tuo conto.</p>"
|
||||||
"\t\t\t\t"
|
|
||||||
|
|
||||||
#: 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"
|
msgid "remove"
|
||||||
msgstr "entfernen"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
" <p>Thanks to the <a href='%s'>OKAPI Framework</a> you "
|
||||||
"external applications\n"
|
"can grant external applications\n"
|
||||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
" access to your <b>%s</b> account. Currently no "
|
||||||
"authorized to act\n"
|
"applications are authorized to act\n"
|
||||||
"\t\t\t\t\ton your behalf. Once you start using external Opencaching "
|
" on your behalf. Once you start using external "
|
||||||
"applications, they will appear here.</p>\n"
|
"Opencaching applications, they will appear here.</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Grazie al <a href='%s'>framework OKAPI</a>puoi concedere ad "
|
"<p>Grazie al <a href='%s'>framework OKAPI</a>puoi concedere ad applicazioni "
|
||||||
"applicazioni esterne\n"
|
"esterne\n"
|
||||||
"\t\t\t\t\t l'accesso al tuo account <b>%s</b>. Attualmente non ci son "
|
"l'accesso al tuo account <b>%s</b>. Attualmente non ci son applicazioni "
|
||||||
"applicazioni autorizzate\n"
|
"autorizzate\n"
|
||||||
"\t\t\t\t\tad agire per tuo conto. Quando userai applicazioni esterne a "
|
"ad agire per tuo conto. Quando userai applicazioni esterne a Opencaching, "
|
||||||
"Opencaching, queste appariranno qui</p>\n"
|
"queste appariranno qui</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
|
|
||||||
#~ msgid "Recommending is allowed only for 'Found it' logtypes."
|
#~ msgid "Recommending is allowed only for 'Found it' logtypes."
|
||||||
#~ msgstr "Le raccomandazioni sono ammesse solo per i log di tipo 'Trovata'"
|
#~ msgstr "Le raccomandazioni sono ammesse solo per i log di tipo 'Trovata'"
|
||||||
|
|||||||
@@ -4,53 +4,53 @@ namespace okapi;
|
|||||||
|
|
||||||
class Locales
|
class Locales
|
||||||
{
|
{
|
||||||
public static $languages = array(
|
public static $languages = array(
|
||||||
'pl' => array('lang' => 'pl', 'locale' => 'pl_PL.utf8', 'name' => 'Polish'),
|
'pl' => array('lang' => 'pl', 'locale' => 'pl_PL.utf8', 'name' => 'Polish'),
|
||||||
'en' => array('lang' => 'en', 'locale' => 'en_US.utf8', 'name' => 'English'),
|
'en' => array('lang' => 'en', 'locale' => 'en_US.utf8', 'name' => 'English'),
|
||||||
'nl' => array('lang' => 'nl', 'locale' => 'nl_NL.utf8', 'name' => 'Dutch'),
|
'nl' => array('lang' => 'nl', 'locale' => 'nl_NL.utf8', 'name' => 'Dutch'),
|
||||||
'de' => array('lang' => 'de', 'locale' => 'de_DE.utf8', 'name' => 'German'),
|
'de' => array('lang' => 'de', 'locale' => 'de_DE.utf8', 'name' => 'German'),
|
||||||
'it' => array('lang' => 'it', 'locale' => 'it_IT.utf8', 'name' => 'Italian'),
|
'it' => array('lang' => 'it', 'locale' => 'it_IT.utf8', 'name' => 'Italian'),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of locales that should be installed on the system in order
|
* Get the list of locales that should be installed on the system in order
|
||||||
* for all translations to work properly.
|
* for all translations to work properly.
|
||||||
*/
|
*/
|
||||||
public static function get_required_locales()
|
public static function get_required_locales()
|
||||||
{
|
{
|
||||||
$arr = array('POSIX');
|
$arr = array('POSIX');
|
||||||
foreach (self::$languages as $key => $value)
|
foreach (self::$languages as $key => $value)
|
||||||
$arr[] = $value['locale'];
|
$arr[] = $value['locale'];
|
||||||
return $arr;
|
return $arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of locales installed on the current system.
|
* Get the list of locales installed on the current system.
|
||||||
*/
|
*/
|
||||||
public static function get_installed_locales()
|
public static function get_installed_locales()
|
||||||
{
|
{
|
||||||
$arr = array();
|
$arr = array();
|
||||||
foreach (explode("\n", shell_exec("locale -a")) as $item)
|
foreach (explode("\n", shell_exec("locale -a")) as $item)
|
||||||
if ($item)
|
if ($item)
|
||||||
$arr[] = $item;
|
$arr[] = $item;
|
||||||
return $arr;
|
return $arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function get_locale_for_language($lang)
|
private static function get_locale_for_language($lang)
|
||||||
{
|
{
|
||||||
if (isset(self::$languages[$lang]))
|
if (isset(self::$languages[$lang]))
|
||||||
return self::$languages[$lang]['locale'];
|
return self::$languages[$lang]['locale'];
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function get_best_locale($langprefs)
|
public static function get_best_locale($langprefs)
|
||||||
{
|
{
|
||||||
foreach ($langprefs as $lang)
|
foreach ($langprefs as $lang)
|
||||||
{
|
{
|
||||||
$locale = self::get_locale_for_language($lang);
|
$locale = self::get_locale_for_language($lang);
|
||||||
if ($locale != null)
|
if ($locale != null)
|
||||||
return $locale;
|
return $locale;
|
||||||
}
|
}
|
||||||
return self::$languages['en']['locale'];
|
return self::$languages['en']['locale'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -2,9 +2,9 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: OKAPI\n"
|
"Project-Id-Version: OKAPI\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2013-04-10 01:08+0100\n"
|
"POT-Creation-Date: 2014-01-23 16:05+0100\n"
|
||||||
"PO-Revision-Date: 2013-04-10 01:12+0100\n"
|
"PO-Revision-Date: 2014-08-09 03:47+0100\n"
|
||||||
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
"Last-Translator: Harrie Klomp <harrie@harrieklomp.be>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: nl_NL\n"
|
"Language: nl_NL\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@@ -13,50 +13,96 @@ msgstr ""
|
|||||||
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
|
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
|
||||||
"X-Poedit-Basepath: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api\\\n"
|
"X-Poedit-Basepath: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api\\\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\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"
|
"X-Poedit-SearchPath-0: .\n"
|
||||||
|
|
||||||
# For additional waypoints. As in "Stage 1: Parking".
|
# For additional waypoints. As in "Stage 1: Parking".
|
||||||
#: okapi/services/caches/geocaches.php:846
|
#: okapi/services/caches/geocaches.php:957
|
||||||
msgid "Stage"
|
msgid "Stage"
|
||||||
msgstr "Etappe"
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||||
"a> site."
|
"a> site."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Deze <a href='%s'>geocache</a> beschrijving komt van de <a href='%s'>%s</a> "
|
||||||
|
"\"\"site."
|
||||||
|
|
||||||
#: okapi/services/caches/geocaches.php:1021
|
#: okapi/services/caches/geocaches.php:1312
|
||||||
#, php-format
|
#, fuzzy, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
"© <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 "
|
"creativecommons.org/licenses/by-nc-nd/3.0/de/deed.en'>CC-BY-NC-ND</a>, as of "
|
||||||
"%s; all log entries © their authors"
|
"%s; all log entries © their authors"
|
||||||
msgstr ""
|
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
|
#: okapi/services/caches/geocaches.php:1323
|
||||||
#, php-format
|
#, fuzzy, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
"© <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 "
|
"creativecommons.org/licenses/by-nc-nd/3.0/de/deed.en'>CC-BY-NC-ND</a>; all "
|
||||||
"log entries © their authors"
|
"log entries © their authors"
|
||||||
msgstr ""
|
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/gpx.php:360
|
||||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:48
|
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"
|
msgid "hidden by"
|
||||||
msgstr "geplaatst door"
|
msgstr "geplaatst door"
|
||||||
|
|
||||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:50
|
#: okapi/services/caches/formatters/gpxfile.tpl.php:64
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d recommendation"
|
msgid "%d recommendation"
|
||||||
msgid_plural "%d recommendations"
|
msgid_plural "%d recommendations"
|
||||||
msgstr[0] "%d aanbeveling"
|
msgstr[0] "%d aanbeveling"
|
||||||
msgstr[1] "%d aanbevelingen"
|
msgstr[1] "%d aanbevelingen"
|
||||||
|
|
||||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:51
|
#: okapi/services/caches/formatters/gpxfile.tpl.php:65
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "found %d time"
|
msgid "found %d time"
|
||||||
msgid_plural "found %d times"
|
msgid_plural "found %d times"
|
||||||
@@ -64,37 +110,42 @@ msgstr[0] "%d keer gevonden"
|
|||||||
msgstr[1] "%d keren gevonden"
|
msgstr[1] "%d keren gevonden"
|
||||||
|
|
||||||
# Generic term for trackable items (like geocoins and travelbugs).
|
# 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
|
#, php-format
|
||||||
msgid "%d trackable"
|
msgid "%d trackable"
|
||||||
msgid_plural "%d trackables"
|
msgid_plural "%d trackables"
|
||||||
msgstr[0] "%d trackable"
|
msgstr[0] "%d trackable"
|
||||||
msgstr[1] "%d trackables"
|
msgstr[1] "%d trackables"
|
||||||
|
|
||||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:58
|
#: okapi/services/caches/formatters/gpxfile.tpl.php:72
|
||||||
msgid "Personal notes"
|
msgid "Personal notes"
|
||||||
msgstr "Persoonlijke notities"
|
msgstr "Persoonlijke notities"
|
||||||
|
|
||||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:62
|
#: okapi/services/caches/formatters/gpxfile.tpl.php:76
|
||||||
msgid "Attributes"
|
msgid "Attributes"
|
||||||
msgstr "Attributen"
|
msgstr "Attributen"
|
||||||
|
|
||||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:66
|
#: okapi/services/caches/formatters/gpxfile.tpl.php:80
|
||||||
msgid "Trackables"
|
msgid "Trackables"
|
||||||
msgstr "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"
|
msgid "Images"
|
||||||
msgstr "Afbeeldingen"
|
msgstr "Afbeeldingen"
|
||||||
|
|
||||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:91
|
#: okapi/services/caches/formatters/gpxfile.tpl.php:113
|
||||||
msgid "Spoilers"
|
msgid "Spoilers"
|
||||||
msgstr "Spoilers"
|
msgstr "Spoilers"
|
||||||
|
|
||||||
#: okapi/services/caches/formatters/gpxfile.tpl.php:99
|
#: okapi/services/caches/formatters/gpxfile.tpl.php:122
|
||||||
msgid "Image descriptions"
|
msgid "Image descriptions"
|
||||||
msgstr "Afbeelding omschrijving"
|
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
|
#: okapi/services/logs/submit.php:70
|
||||||
msgid ""
|
msgid ""
|
||||||
"You are trying to publish a log entry with a date in future. Cache log "
|
"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 "
|
"De cachewaardering is genegeerd, omdat %s geen waarderingen in het systeem "
|
||||||
"heeft."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
||||||
"support this feature."
|
"support this feature."
|
||||||
msgstr ""
|
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.
|
# Missing "you can attend it"
|
||||||
#: okapi/services/logs/submit.php:131
|
#: okapi/services/logs/submit.php:145
|
||||||
msgid ""
|
msgid ""
|
||||||
"This cache is an Event cache. You cannot \"Find it\"! (But - you may "
|
"This cache is an Event cache. You cannot \"Find\" it (but you can attend it, "
|
||||||
"\"Comment\" on it.)"
|
"or comment on it)!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Dit is een eventcache. Deze kan niet als \"Gevonden\" gelogd worden. Maar "
|
"Dit is een evenement. Deze kan niet als \"Gevonden\" gelogd worden. (maar "
|
||||||
"wel als \"Notitie\"."
|
"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."
|
msgid "Your have to supply some text for your comment."
|
||||||
msgstr "Er dient enige tekst ingevuld te worden."
|
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!"
|
msgid "This cache requires a password. You didn't provide one!"
|
||||||
msgstr "Deze cache vraagt om een wachtwoord. Deze is niet opgegeven!"
|
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!"
|
msgid "Invalid password!"
|
||||||
msgstr "Verkeerd wachtwoord!"
|
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.
|
# 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."
|
msgid "You have already submitted a log entry with exactly the same contents."
|
||||||
msgstr "Deze log is reeds met dezelfde tekst verzonden."
|
msgstr "Deze log is reeds met dezelfde tekst verzonden."
|
||||||
|
|
||||||
#: okapi/services/logs/submit.php:279
|
#: okapi/services/logs/submit.php:308
|
||||||
msgid ""
|
msgid ""
|
||||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||||
"\"Comments\" only!"
|
"\"Comments\" only!"
|
||||||
@@ -153,25 +223,29 @@ msgstr ""
|
|||||||
"Je hebt deze cache al als \"Gevonden\" gelogd. Je kunt nu wel een \"Notitie"
|
"Je hebt deze cache al als \"Gevonden\" gelogd. Je kunt nu wel een \"Notitie"
|
||||||
"\" plaatsen."
|
"\" plaatsen."
|
||||||
|
|
||||||
# The English text was changed from "you cannot rate it" to "you cannot find it". The translation remained.
|
#: okapi/services/logs/submit.php:310
|
||||||
#: okapi/services/logs/submit.php:281
|
|
||||||
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||||
msgstr ""
|
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."
|
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Je hebt deze cache al gewaardeerd. De waardering kan niet veranderd worden."
|
"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."
|
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!"
|
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."
|
msgid "Your cache log entry was posted successfully."
|
||||||
msgstr "De log is succesvol verzonden."
|
msgstr "De log is succesvol verzonden."
|
||||||
|
|
||||||
@@ -208,35 +282,33 @@ msgstr "Toestemmen"
|
|||||||
msgid "Decline"
|
msgid "Decline"
|
||||||
msgstr "Afwijzen"
|
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.
|
# 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
|
# Sample: http://i.imgur.com/ZCJNT.png
|
||||||
#: okapi/views/apps/authorize.tpl.php:56
|
#: okapi/views/apps/authorize.tpl.php:56
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
" <p>Once permission is granted it is valid until its "
|
||||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
"withdrawal on\n"
|
||||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
" the <a href='%s'>applications management</a> page.</p>\n"
|
||||||
"OKAPI Framework</a>.\n"
|
" <p>The application will access your acount via <a "
|
||||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
"href='%s'>the OKAPI Framework</a>.\n"
|
||||||
"methods delivered\n"
|
" If you allow this request application will be able to "
|
||||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
"access all methods delivered\n"
|
||||||
"name.\n"
|
" by the OKAPI Framework, i.e. post log entries on "
|
||||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
"geocaches in your name.\n"
|
||||||
"\t\t\t\t"
|
" You can revoke this permission at any moment.</p>\n"
|
||||||
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Wanneer toegestemd is blijft deze geldig tot intrekking op\n"
|
"<p>Wanneer toegestemd is blijft deze geldig tot intrekking op\n"
|
||||||
"\t\t\t\t\tde <a href='%s'>toepassingsbeheer</a> pagina.</p>\n"
|
"de <a href='%s'>toepassingsbeheer</a> pagina.</p>\n"
|
||||||
"\t\t\t\t\t<p>De toepassing zal toegang krijgen via jouw account op <a "
|
"<p>De toepassing zal toegang krijgen via jouw account op <a href='%s'>the "
|
||||||
"href='%s'>the OKAPI Framework</a>.\n"
|
"OKAPI Framework</a>.\n"
|
||||||
"\t\t\t\t\tWanneer je toestemming geeft voor deze toepassing zullen de "
|
"Wanneer je toestemming geeft voor deze toepassing zullen de mogelijkheden\n"
|
||||||
"mogelijkheden\n"
|
"van OKAPI Framework toegepast worden, b.v. het loggen van een cache.\n"
|
||||||
"\t\t\t\t\tvan OKAPI Framework toegepast worden, b.v. het loggen van een "
|
"De toestemming kan elk moment ingetrokken worden.</p>"
|
||||||
"cache.\n"
|
|
||||||
"\t\t\t\t\tDe toestemming kan elk moment ingetrokken worden.</p>\n"
|
|
||||||
"\t\t\t\t"
|
|
||||||
|
|
||||||
#: okapi/views/apps/authorized.tpl.php:5
|
#: okapi/views/apps/authorized.tpl.php:5
|
||||||
msgid "Authorization Succeeded"
|
msgid "Authorization Succeeded"
|
||||||
@@ -251,18 +323,16 @@ msgstr "Met succes toegang verleend"
|
|||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
" <p><b>You've just granted %s application access to your %s "
|
||||||
"b>\n"
|
"account.</b>\n"
|
||||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
" To complete the operation, go back to %s and enter the "
|
||||||
"code:</p>\n"
|
"following PIN code:</p>\n"
|
||||||
"\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t<p><b>Je hebt toegang verleent voor %s toepassing op jouw %s account."
|
"<p><b>Je hebt toegang verleent voor %s toepassing op jouw %s account.</b>\n"
|
||||||
"</b>\n"
|
"Om de actie te voltooien, ga terug naar %s en gebruik de volgende PIN code:</"
|
||||||
"\t\t\t\tOm de aktie te voltooien, ga terug naar %s en gebruik de volgende "
|
"p>"
|
||||||
"PIN code:</p>\n"
|
|
||||||
"\t\t\t"
|
|
||||||
|
|
||||||
#: okapi/views/apps/index.tpl.php:5
|
#: okapi/views/apps/index.tpl.php:5
|
||||||
msgid "My Apps"
|
msgid "My Apps"
|
||||||
@@ -273,29 +343,25 @@ msgid "Your external applications"
|
|||||||
msgstr "Jouw externe toepassingen"
|
msgstr "Jouw externe toepassingen"
|
||||||
|
|
||||||
# This will be shown when user visits /okapi/apps page.
|
# This will be shown when user visits /okapi/apps page.
|
||||||
# Sample: http://i.imgur.com/ZCJNT.png
|
|
||||||
#: okapi/views/apps/index.tpl.php:31
|
#: okapi/views/apps/index.tpl.php:31
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
" <p>This is the list of applications which you granted "
|
||||||
"your <b>%s</b> account.\n"
|
"access to your <b>%s</b> account.\n"
|
||||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
" This page gives you the abbility to revoke all "
|
||||||
"privileges.\n"
|
"previously granted privileges.\n"
|
||||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
" Once you click \"remove\" the application will no longer "
|
||||||
"to perform any\n"
|
"be able to perform any\n"
|
||||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
" actions on your behalf.</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Dit is een lijst met toegestane toepassingen op jouw <b>%s</b> "
|
"<p>Dit is een lijst met toegestane toepassingen op jouw <b>%s</b> account.\n"
|
||||||
"account.\n"
|
"Op deze pagina kun je alle toestemmingen intrekken die gegeven zijn.\n"
|
||||||
"\t\t\t\t\tOp deze pagina kun je alle toestemmingen intrekken die gegeven "
|
"Met een klik op \"verwijderen\" zal de toepassing verwijderen en is dan ook "
|
||||||
"zijn.\n"
|
"niet meer beschikbaar\n"
|
||||||
"\t\t\t\t\tMet een klik op \"verwijderen\" zal de toepassing verwijderen en "
|
"oor anderen.</p>"
|
||||||
"is dan ook niet meer beschikbaar\n"
|
|
||||||
"\t\t\t\t\voor anderen.</p>\n"
|
|
||||||
"\t\t\t\t"
|
|
||||||
|
|
||||||
#: okapi/views/apps/index.tpl.php:45
|
#: okapi/views/apps/index.tpl.php:45
|
||||||
msgid "remove"
|
msgid "remove"
|
||||||
@@ -305,22 +371,21 @@ msgstr "verwijderen"
|
|||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
" <p>Thanks to the <a href='%s'>OKAPI Framework</a> you "
|
||||||
"external applications\n"
|
"can grant external applications\n"
|
||||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
" access to your <b>%s</b> account. Currently no "
|
||||||
"authorized to act\n"
|
"applications are authorized to act\n"
|
||||||
"\t\t\t\t\ton your behalf. Once you start using external Opencaching "
|
" on your behalf. Once you start using external "
|
||||||
"applications, they will appear here.</p>\n"
|
"Opencaching applications, they will appear here.</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Dankzij het <a href='%s'>OKAPI Framework</a> kun je toegang "
|
"<p>Dankzij het <a href='%s'>OKAPI Framework</a> kun je toegang verlenen via "
|
||||||
"verlenen via externe\n"
|
"externe\n"
|
||||||
"\t\t\t\t\ttoepassingen op een <b>%s</b> account. Momenteel zijn op dit "
|
"toepassingen op een <b>%s</b> account. Momenteel zijn op dit account nog "
|
||||||
"account nog geen externe\n"
|
"geen externe\n"
|
||||||
"\t\t\t\t\ttoepassingen actief. Geactiveerde Opencaching toepassingen "
|
"toepassingen actief. Geactiveerde Opencaching toepassingen zullen hier "
|
||||||
"zullen hier getoond worden.</p>\n"
|
"getoond worden.</p>"
|
||||||
"\t\t\t\t"
|
|
||||||
|
|
||||||
#~ msgid ""
|
#~ msgid ""
|
||||||
#~ "This cache is archived. Only admins and the owner are allowed to add a "
|
#~ "This cache is archived. Only admins and the owner are allowed to add a "
|
||||||
|
|||||||
Binary file not shown.
@@ -2,8 +2,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: OKAPI\n"
|
"Project-Id-Version: OKAPI\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2013-07-11 08:28+0100\n"
|
"POT-Creation-Date: 2014-01-23 15:48+0100\n"
|
||||||
"PO-Revision-Date: 2013-07-11 08:35+0100\n"
|
"PO-Revision-Date: 2014-01-23 15:49+0100\n"
|
||||||
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: pl_PL\n"
|
"Language: pl_PL\n"
|
||||||
@@ -15,26 +15,35 @@ msgstr ""
|
|||||||
"\\okapi\n"
|
"\\okapi\n"
|
||||||
"Plural-Forms: nplurals=3; plural= n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
"Plural-Forms: nplurals=3; plural= n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||||
"|| n%100>=20) ? 1 : 2;\n"
|
"|| n%100>=20) ? 1 : 2;\n"
|
||||||
"X-Poedit-SourceCharset: utf-8\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: .\n"
|
"X-Poedit-SearchPath-0: .\n"
|
||||||
|
|
||||||
#: services/caches/geocaches.php:956
|
#: services/caches/geocaches.php:957
|
||||||
msgid "Stage"
|
msgid "Stage"
|
||||||
msgstr "Etap"
|
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"
|
msgid "National Park / Landscape"
|
||||||
msgstr "Park narodowy lub krajobrazowy"
|
msgstr "Park narodowy lub krajobrazowy"
|
||||||
|
|
||||||
#: services/caches/geocaches.php:1263
|
#: services/caches/geocaches.php:1300
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||||
"a> site."
|
"a> site."
|
||||||
msgstr "Opis <a href='%s'>skrzynki</a> pochodzi z serwisu <a href='%s'>%s</a>."
|
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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
"© <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 "
|
"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."
|
"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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
"© <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 "
|
"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."
|
"autorskie wpisów do logów należą do ich autorów."
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:31
|
#: services/caches/formatters/gpx.php:360
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:60
|
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"
|
msgid "hidden by"
|
||||||
msgstr "ukryta przez"
|
msgstr "ukryta przez"
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:62
|
#: services/caches/formatters/gpxfile.tpl.php:64
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d recommendation"
|
msgid "%d recommendation"
|
||||||
msgid_plural "%d recommendations"
|
msgid_plural "%d recommendations"
|
||||||
@@ -69,7 +103,7 @@ msgstr[0] "%d rekomendacja"
|
|||||||
msgstr[1] "%d rekomendacje"
|
msgstr[1] "%d rekomendacje"
|
||||||
msgstr[2] "%d rekomendacji"
|
msgstr[2] "%d rekomendacji"
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:63
|
#: services/caches/formatters/gpxfile.tpl.php:65
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "found %d time"
|
msgid "found %d time"
|
||||||
msgid_plural "found %d times"
|
msgid_plural "found %d times"
|
||||||
@@ -77,7 +111,7 @@ msgstr[0] "znaleziona %d raz"
|
|||||||
msgstr[1] "znaleziona %d razy"
|
msgstr[1] "znaleziona %d razy"
|
||||||
msgstr[2] "znaleziona %d razy"
|
msgstr[2] "znaleziona %d razy"
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:66
|
#: services/caches/formatters/gpxfile.tpl.php:68
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d trackable"
|
msgid "%d trackable"
|
||||||
msgid_plural "%d trackables"
|
msgid_plural "%d trackables"
|
||||||
@@ -85,32 +119,32 @@ msgstr[0] "%d GeoKret (lub TravelBug)"
|
|||||||
msgstr[1] "%d GeoKrety (lub TravelBugi)"
|
msgstr[1] "%d GeoKrety (lub TravelBugi)"
|
||||||
msgstr[2] "%d GeoKretów (lub TravelBugów)"
|
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"
|
msgid "Personal notes"
|
||||||
msgstr "Osobiste notatki"
|
msgstr "Osobiste notatki"
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:74
|
#: services/caches/formatters/gpxfile.tpl.php:76
|
||||||
msgid "Attributes"
|
msgid "Attributes"
|
||||||
msgstr "Atrybuty"
|
msgstr "Atrybuty"
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:78
|
#: services/caches/formatters/gpxfile.tpl.php:80
|
||||||
msgid "Trackables"
|
msgid "Trackables"
|
||||||
msgstr "Geokrety, Travelbugi itp."
|
msgstr "Geokrety, Travelbugi itp."
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:88
|
#: services/caches/formatters/gpxfile.tpl.php:90
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:104
|
#: services/caches/formatters/gpxfile.tpl.php:106
|
||||||
msgid "Images"
|
msgid "Images"
|
||||||
msgstr "Obrazki"
|
msgstr "Obrazki"
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:111
|
#: services/caches/formatters/gpxfile.tpl.php:113
|
||||||
msgid "Spoilers"
|
msgid "Spoilers"
|
||||||
msgstr "Spoilery"
|
msgstr "Spoilery"
|
||||||
|
|
||||||
#: services/caches/formatters/gpxfile.tpl.php:120
|
#: services/caches/formatters/gpxfile.tpl.php:122
|
||||||
msgid "Image descriptions"
|
msgid "Image descriptions"
|
||||||
msgstr "Opisy obrazków"
|
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:"
|
msgid "The cache probably is located in the following protection areas:"
|
||||||
msgstr "Prawdopodobnie skrzynka znajduje się na terenie obszarów chronionych:"
|
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!"
|
msgid "Invalid password!"
|
||||||
msgstr "Niepoprawne hasło!"
|
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."
|
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ą."
|
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 ""
|
msgid ""
|
||||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||||
"\"Comments\" only!"
|
"\"Comments\" only!"
|
||||||
@@ -189,30 +223,30 @@ msgstr ""
|
|||||||
"Już opublikowałeś jeden wpis typu \"Znaleziona\" dla tej skrzynki. Teraz "
|
"Już opublikowałeś jeden wpis typu \"Znaleziona\" dla tej skrzynki. Teraz "
|
||||||
"możesz dodawać jedynie \"Komentarze\"!"
|
"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!"
|
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Jesteś właścicielem tej skrzynki. Możesz przesyłać jedynie \"Komentarze\"."
|
"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."
|
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."
|
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."
|
msgid "You have already recommended this cache once."
|
||||||
msgstr "Już raz zarekomendowałeś tę skrzynkę."
|
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!"
|
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Aktualnie nie możesz wystawić kolejnej rekomendacji. Znajdź najpierw więcej "
|
"Aktualnie nie możesz wystawić kolejnej rekomendacji. Znajdź najpierw więcej "
|
||||||
"skrzynek!"
|
"skrzynek!"
|
||||||
|
|
||||||
#: services/logs/submit.php:395
|
#: services/logs/submit.php:398
|
||||||
msgid "Event caches cannot \"need maintenance\"."
|
msgid "Event caches cannot \"need maintenance\"."
|
||||||
msgstr "Skrzynki typu Wydarzenie nie mogą \"potrzebować serwisu\"."
|
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."
|
msgid "Your cache log entry was posted successfully."
|
||||||
msgstr "Twój wpis do logbooka został opublikowany pomyślnie."
|
msgstr "Twój wpis do logbooka został opublikowany pomyślnie."
|
||||||
|
|
||||||
@@ -253,16 +287,17 @@ msgstr "Odmawiam"
|
|||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
" <p>Once permission is granted it is valid until its "
|
||||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
"withdrawal on\n"
|
||||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
" the <a href='%s'>applications management</a> page.</p>\n"
|
||||||
"OKAPI Framework</a>.\n"
|
" <p>The application will access your acount via <a "
|
||||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
"href='%s'>the OKAPI Framework</a>.\n"
|
||||||
"methods delivered\n"
|
" If you allow this request application will be able to "
|
||||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
"access all methods delivered\n"
|
||||||
"name.\n"
|
" by the OKAPI Framework, i.e. post log entries on "
|
||||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
"geocaches in your name.\n"
|
||||||
"\t\t\t\t"
|
" You can revoke this permission at any moment.</p>\n"
|
||||||
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p>Raz udzielona zgoda jest ważna aż do momentu jej wycofania na stronie <a "
|
"<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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
" <p><b>You've just granted %s application access to your %s "
|
||||||
"b>\n"
|
"account.</b>\n"
|
||||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
" To complete the operation, go back to %s and enter the "
|
||||||
"code:</p>\n"
|
"following PIN code:</p>\n"
|
||||||
"\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p><b>Właśnie dałeś dostęp aplikacji %s do Twojego konta %s.</b>\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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
" <p>This is the list of applications which you granted "
|
||||||
"your <b>%s</b> account.\n"
|
"access to your <b>%s</b> account.\n"
|
||||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
" This page gives you the abbility to revoke all "
|
||||||
"privileges.\n"
|
"previously granted privileges.\n"
|
||||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
" Once you click \"remove\" the application will no longer "
|
||||||
"to perform any\n"
|
"be able to perform any\n"
|
||||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
" actions on your behalf.</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p>Następującym aplikacjom zezwoliłeś na dostęp do swojego konta <b>%s</b>.\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
|
#, php-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
" <p>Thanks to the <a href='%s'>OKAPI Framework</a> you "
|
||||||
"external applications\n"
|
"can grant external applications\n"
|
||||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
" access to your <b>%s</b> account. Currently no "
|
||||||
"authorized to act\n"
|
"applications are authorized to act\n"
|
||||||
"\t\t\t\t\ton your behalf. Once you start using external Opencaching "
|
" on your behalf. Once you start using external "
|
||||||
"applications, they will appear here.</p>\n"
|
"Opencaching applications, they will appear here.</p>\n"
|
||||||
"\t\t\t\t"
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"<p>Dzięki platformie <a href='%s'>OKAPI</a> możesz dawać zewnętrznym "
|
"<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 "
|
"w Twoim imieniu. Gdy zaczniesz korzystać z zewnętrznych aplikacji, ich lista "
|
||||||
"pojawi się tutaj.</p>"
|
"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."
|
#~ msgid "Recommending is allowed only for 'Found it' logtypes."
|
||||||
#~ msgstr "Rekomendacje są dozwolone jedynie z wpisem \"Znaleziona\"."
|
#~ msgstr "Rekomendacje są dozwolone jedynie z wpisem \"Znaleziona\"."
|
||||||
|
|
||||||
|
|||||||
@@ -839,6 +839,9 @@ class OAuthServer {
|
|||||||
if( ! $timestamp )
|
if( ! $timestamp )
|
||||||
throw new OAuthMissingParameterException('oauth_timestamp');
|
throw new OAuthMissingParameterException('oauth_timestamp');
|
||||||
|
|
||||||
|
// Cast to integer. See issue #314.
|
||||||
|
$timestamp = $timestamp + 0;
|
||||||
|
|
||||||
// verify that timestamp is recentish
|
// verify that timestamp is recentish
|
||||||
$now = time();
|
$now = time();
|
||||||
if (abs($now - $timestamp) > $this->timestamp_threshold) {
|
if (abs($now - $timestamp) > $this->timestamp_threshold) {
|
||||||
|
|||||||
@@ -6,186 +6,187 @@ use Exception;
|
|||||||
|
|
||||||
class OkapiServiceRunner
|
class OkapiServiceRunner
|
||||||
{
|
{
|
||||||
#
|
#
|
||||||
# This the list of all available OKAPI methods. All methods on this list become
|
# 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
|
# 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
|
# 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
|
# 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
|
# 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).
|
# (you may describe it as "internal" and accessible to selected consumer keys only).
|
||||||
#
|
#
|
||||||
public static $all_names = array(
|
public static $all_names = array(
|
||||||
# Valid format: ^services/[0-9a-z_/]*$ (it means you may use only alphanumeric
|
# Valid format: ^services/[0-9a-z_/]*$ (it means you may use only alphanumeric
|
||||||
# characters and the "_" sign in your method names).
|
# characters and the "_" sign in your method names).
|
||||||
'services/apisrv/installation',
|
'services/apisrv/installation',
|
||||||
'services/apisrv/installations',
|
'services/apisrv/installations',
|
||||||
'services/apisrv/stats',
|
'services/apisrv/stats',
|
||||||
'services/apiref/method',
|
'services/apiref/method',
|
||||||
'services/apiref/method_index',
|
'services/apiref/method_index',
|
||||||
'services/apiref/issue',
|
'services/apiref/issue',
|
||||||
'services/attrs/attribute_index',
|
'services/attrs/attribute_index',
|
||||||
'services/attrs/attribute',
|
'services/attrs/attribute',
|
||||||
'services/attrs/attributes',
|
'services/attrs/attributes',
|
||||||
'services/oauth/request_token',
|
'services/oauth/request_token',
|
||||||
'services/oauth/authorize',
|
'services/oauth/authorize',
|
||||||
'services/oauth/access_token',
|
'services/oauth/access_token',
|
||||||
'services/caches/search/all',
|
'services/caches/search/all',
|
||||||
'services/caches/search/bbox',
|
'services/caches/search/bbox',
|
||||||
'services/caches/search/nearest',
|
'services/caches/search/nearest',
|
||||||
'services/caches/search/by_urls',
|
'services/caches/search/by_urls',
|
||||||
'services/caches/search/save',
|
'services/caches/search/save',
|
||||||
'services/caches/shortcuts/search_and_retrieve',
|
'services/caches/shortcuts/search_and_retrieve',
|
||||||
'services/caches/geocache',
|
'services/caches/geocache',
|
||||||
'services/caches/geocaches',
|
'services/caches/geocaches',
|
||||||
'services/caches/mark',
|
'services/caches/mark',
|
||||||
'services/caches/formatters/gpx',
|
'services/caches/save_personal_notes',
|
||||||
'services/caches/formatters/garmin',
|
'services/caches/formatters/gpx',
|
||||||
'services/caches/map/tile',
|
'services/caches/formatters/garmin',
|
||||||
'services/logs/entries',
|
'services/caches/map/tile',
|
||||||
'services/logs/entry',
|
'services/logs/entries',
|
||||||
'services/logs/logs',
|
'services/logs/entry',
|
||||||
'services/logs/userlogs',
|
'services/logs/logs',
|
||||||
'services/logs/submit',
|
'services/logs/userlogs',
|
||||||
'services/users/user',
|
'services/logs/submit',
|
||||||
'services/users/users',
|
'services/users/user',
|
||||||
'services/users/by_usernames',
|
'services/users/users',
|
||||||
'services/users/by_username',
|
'services/users/by_usernames',
|
||||||
'services/users/by_internal_id',
|
'services/users/by_username',
|
||||||
'services/users/by_internal_ids',
|
'services/users/by_internal_id',
|
||||||
'services/replicate/changelog',
|
'services/users/by_internal_ids',
|
||||||
'services/replicate/fulldump',
|
'services/replicate/changelog',
|
||||||
'services/replicate/info',
|
'services/replicate/fulldump',
|
||||||
);
|
'services/replicate/info',
|
||||||
|
);
|
||||||
|
|
||||||
/** Check if method exists. */
|
/** Check if method exists. */
|
||||||
public static function exists($service_name)
|
public static function exists($service_name)
|
||||||
{
|
{
|
||||||
return in_array($service_name, self::$all_names);
|
return in_array($service_name, self::$all_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get method options (is consumer required etc.). */
|
/** Get method options (is consumer required etc.). */
|
||||||
public static function options($service_name)
|
public static function options($service_name)
|
||||||
{
|
{
|
||||||
if (!self::exists($service_name))
|
if (!self::exists($service_name))
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
require_once($GLOBALS['rootpath']."okapi/$service_name.php");
|
require_once($GLOBALS['rootpath']."okapi/$service_name.php");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return call_user_func(array('\\okapi\\'.
|
return call_user_func(array('\\okapi\\'.
|
||||||
str_replace('/', '\\', $service_name).'\\WebService', 'options'));
|
str_replace('/', '\\', $service_name).'\\WebService', 'options'));
|
||||||
} catch (Exception $e)
|
} catch (Exception $e)
|
||||||
{
|
{
|
||||||
throw new Exception("Make sure you've declared your WebService class ".
|
throw new Exception("Make sure you've declared your WebService class ".
|
||||||
"in an valid namespace (".'okapi\\'.str_replace('/', '\\', $service_name)."); ".
|
"in an valid namespace (".'okapi\\'.str_replace('/', '\\', $service_name)."); ".
|
||||||
$e->getMessage());
|
$e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get method documentation file contents (stuff within the XML file).
|
* Get method documentation file contents (stuff within the XML file).
|
||||||
* If you're looking for a parsed representation, use services/apiref/method.
|
* If you're looking for a parsed representation, use services/apiref/method.
|
||||||
*/
|
*/
|
||||||
public static function docs($service_name)
|
public static function docs($service_name)
|
||||||
{
|
{
|
||||||
if (!self::exists($service_name))
|
if (!self::exists($service_name))
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
try {
|
try {
|
||||||
return file_get_contents("$service_name.xml", true);
|
return file_get_contents("$service_name.xml", true);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw new Exception("Missing documentation file: $service_name.xml");
|
throw new Exception("Missing documentation file: $service_name.xml");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the method and return the result.
|
* Execute the method and return the result.
|
||||||
*
|
*
|
||||||
* OKAPI methods return OkapiHttpResponses, but some MAY also return
|
* OKAPI methods return OkapiHttpResponses, but some MAY also return
|
||||||
* PHP objects (see OkapiRequest::construct_inside_request for details).
|
* PHP objects (see OkapiRequest::construct_inside_request for details).
|
||||||
*
|
*
|
||||||
* If $request must be consistent with given method's options (must
|
* If $request must be consistent with given method's options (must
|
||||||
* include Consumer and Token, if they are required).
|
* include Consumer and Token, if they are required).
|
||||||
*/
|
*/
|
||||||
public static function call($service_name, OkapiRequest $request)
|
public static function call($service_name, OkapiRequest $request)
|
||||||
{
|
{
|
||||||
Okapi::init_internals();
|
Okapi::init_internals();
|
||||||
|
|
||||||
if (!self::exists($service_name))
|
if (!self::exists($service_name))
|
||||||
throw new Exception("Method does not exist: '$service_name'");
|
throw new Exception("Method does not exist: '$service_name'");
|
||||||
|
|
||||||
$options = self::options($service_name);
|
$options = self::options($service_name);
|
||||||
if ($options['min_auth_level'] >= 2 && $request->consumer == null)
|
if ($options['min_auth_level'] >= 2 && $request->consumer == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
||||||
"\$request->consumer MAY NOT be empty for Level 2 and Level 3 methods. Provide ".
|
"\$request->consumer MAY NOT be empty for Level 2 and Level 3 methods. Provide ".
|
||||||
"a dummy Consumer if you have to.");
|
"a dummy Consumer if you have to.");
|
||||||
}
|
}
|
||||||
if ($options['min_auth_level'] >= 3 && $request->token == null)
|
if ($options['min_auth_level'] >= 3 && $request->token == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
||||||
"\$request->token MAY NOT be empty for Level 3 methods.");
|
"\$request->token MAY NOT be empty for Level 3 methods.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$time_started = microtime(true);
|
$time_started = microtime(true);
|
||||||
Okapi::gettext_domain_init();
|
Okapi::gettext_domain_init();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
require_once($GLOBALS['rootpath']."okapi/$service_name.php");
|
require_once($GLOBALS['rootpath']."okapi/$service_name.php");
|
||||||
$response = call_user_func(array('\\okapi\\'.
|
$response = call_user_func(array('\\okapi\\'.
|
||||||
str_replace('/', '\\', $service_name).'\\WebService', 'call'), $request);
|
str_replace('/', '\\', $service_name).'\\WebService', 'call'), $request);
|
||||||
Okapi::gettext_domain_restore();
|
Okapi::gettext_domain_restore();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Okapi::gettext_domain_restore();
|
Okapi::gettext_domain_restore();
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
$runtime = microtime(true) - $time_started;
|
$runtime = microtime(true) - $time_started;
|
||||||
|
|
||||||
# Log the request to the stats table. Only valid requests (these which didn't end up
|
# Log the request to the stats table. Only valid requests (these which didn't end up
|
||||||
# with an exception) are logged.
|
# with an exception) are logged.
|
||||||
self::save_stats($service_name, $request, $runtime);
|
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
|
* 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
|
* 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.
|
* version of save_stats which saves runtime stats under the name of $extra_name.
|
||||||
* Note, that $request can be null.
|
* Note, that $request can be null.
|
||||||
*/
|
*/
|
||||||
public static function save_stats_extra($extra_name, $request, $runtime)
|
public static function save_stats_extra($extra_name, $request, $runtime)
|
||||||
{
|
{
|
||||||
self::save_stats("extra/".$extra_name, $request, $runtime);
|
self::save_stats("extra/".$extra_name, $request, $runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function save_stats($service_name, $request, $runtime)
|
private static function save_stats($service_name, $request, $runtime)
|
||||||
{
|
{
|
||||||
# Getting rid of nulls. MySQL PRIMARY keys cannot contain nullable columns.
|
# Getting rid of nulls. MySQL PRIMARY keys cannot contain nullable columns.
|
||||||
# Temp table doesn't have primary key, but other stats tables (which are
|
# Temp table doesn't have primary key, but other stats tables (which are
|
||||||
# dependant on stats table) - do.
|
# dependant on stats table) - do.
|
||||||
|
|
||||||
if ($request !== null) {
|
if ($request !== null) {
|
||||||
$consumer_key = ($request->consumer != null) ? $request->consumer->key : 'anonymous';
|
$consumer_key = ($request->consumer != null) ? $request->consumer->key : 'anonymous';
|
||||||
$user_id = (($request->token != null) && ($request->token instanceof OkapiAccessToken)) ? $request->token->user_id : -1;
|
$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
|
if ($request->is_http_request() && ($service_name[0] == 's')) # 's' for "services/", we don't want "extra/" included
|
||||||
$calltype = 'http';
|
$calltype = 'http';
|
||||||
else
|
else
|
||||||
$calltype = 'internal';
|
$calltype = 'internal';
|
||||||
} else {
|
} else {
|
||||||
$consumer_key = 'internal';
|
$consumer_key = 'internal';
|
||||||
$user_id = -1;
|
$user_id = -1;
|
||||||
$calltype = 'internal';
|
$calltype = 'internal';
|
||||||
}
|
}
|
||||||
|
|
||||||
Db::execute("
|
Db::execute("
|
||||||
insert into okapi_stats_temp (`datetime`, consumer_key, user_id, service_name, calltype, runtime)
|
insert into okapi_stats_temp (`datetime`, consumer_key, user_id, service_name, calltype, runtime)
|
||||||
values (
|
values (
|
||||||
now(),
|
now(),
|
||||||
'".mysql_real_escape_string($consumer_key)."',
|
'".mysql_real_escape_string($consumer_key)."',
|
||||||
'".mysql_real_escape_string($user_id)."',
|
'".mysql_real_escape_string($user_id)."',
|
||||||
'".mysql_real_escape_string($service_name)."',
|
'".mysql_real_escape_string($service_name)."',
|
||||||
'".mysql_real_escape_string($calltype)."',
|
'".mysql_real_escape_string($calltype)."',
|
||||||
'".mysql_real_escape_string($runtime)."'
|
'".mysql_real_escape_string($runtime)."'
|
||||||
);
|
);
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,32 +15,32 @@ use okapi\Cache;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 0
|
'min_auth_level' => 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$issue_id = $request->get_parameter('issue_id');
|
$issue_id = $request->get_parameter('issue_id');
|
||||||
if (!$issue_id)
|
if (!$issue_id)
|
||||||
throw new ParamMissing('issue_id');
|
throw new ParamMissing('issue_id');
|
||||||
if ((!preg_match("/^[0-9]+$/", $issue_id)) || (strlen($issue_id) > 6))
|
if ((!preg_match("/^[0-9]+$/", $issue_id)) || (strlen($issue_id) > 6))
|
||||||
throw new InvalidParam('issue_id');
|
throw new InvalidParam('issue_id');
|
||||||
|
|
||||||
# In October 2013, Google Code feed at:
|
# In October 2013, Google Code feed at:
|
||||||
# http://code.google.com/feeds/issues/p/opencaching-api/issues/$issue_id/comments/full
|
# 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.
|
# stopped working. We are forced to respond with a simple placeholder.
|
||||||
|
|
||||||
$result = array(
|
$result = array(
|
||||||
'id' => $issue_id + 0,
|
'id' => $issue_id + 0,
|
||||||
'last_updated' => null,
|
'last_updated' => null,
|
||||||
'title' => null,
|
'title' => null,
|
||||||
'url' => "https://code.google.com/p/opencaching-api/issues/detail?id=".$issue_id,
|
'url' => "https://code.google.com/p/opencaching-api/issues/detail?id=".$issue_id,
|
||||||
'comment_count' => null
|
'comment_count' => null
|
||||||
);
|
);
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve information on given issue</brief>
|
<brief>Retrieve information on given issue</brief>
|
||||||
<issue-id>11</issue-id>
|
<issue-id>11</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p><b>Important:</b> This method stopped working properly in October 2013.
|
<p><b>Important:</b> This method stopped working properly in October 2013.
|
||||||
Now, it returns a simple placeholder.
|
Now, it returns a simple placeholder.
|
||||||
<a href='https://code.google.com/p/opencaching-api/issues/detail?id=288'>Read more</a>.</p>
|
<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
|
<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.
|
<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
|
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>.
|
<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
|
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>
|
sure if we want them displayed on our documentation pages).</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='issue_id'>
|
<req name='issue_id'>
|
||||||
ID of an Issue.
|
ID of an Issue.
|
||||||
</req>
|
</req>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>id</b> - number of the issue created for this method,</li>
|
<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
|
<li><b>last_updated</b> - date and time (ISO 8601) when the issue was last updated
|
||||||
<b>or null</b> if unknown,</li>
|
<b>or null</b> if unknown,</li>
|
||||||
<li><b>title</b> - issue title <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>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>
|
<li><b>comment_count</b> - total number of submitted comments <b>or null</b> if unknown.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Note, that this will respond with HTTP 400 if we fail to retrieve data from
|
<p>Note, that this will respond with HTTP 400 if we fail to retrieve data from
|
||||||
the Google Code site.</p>
|
the Google Code site.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -14,158 +14,216 @@ use okapi\OkapiInternalConsumer;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 0
|
'min_auth_level' => 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function arg_desc($arg_node)
|
private static function arg_desc($arg_node)
|
||||||
{
|
{
|
||||||
$attrs = $arg_node->attributes();
|
$attrs = $arg_node->attributes();
|
||||||
return array(
|
return array(
|
||||||
'name' => (string)$attrs['name'],
|
'name' => (string)$attrs['name'],
|
||||||
'is_required' => $arg_node->getName() == 'req',
|
'is_required' => $arg_node->getName() == 'req',
|
||||||
'is_deprecated' => (isset($attrs['class']) && (strpos($attrs['class'], 'deprecated') !== false)),
|
'is_deprecated' => (isset($attrs['class']) && (strpos($attrs['class'], 'deprecated') !== false)),
|
||||||
'class' => 'public',
|
'class' => 'public',
|
||||||
'description' =>
|
'description' =>
|
||||||
(isset($attrs['default']) ? ("<p>Default value: <b>".$attrs['default']."</b></p>") : "").
|
(isset($attrs['default']) ? ("<p>Default value: <b>".$attrs['default']."</b></p>") : "").
|
||||||
self::get_inner_xml($arg_node),
|
self::get_inner_xml($arg_node),
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function get_inner_xml($node)
|
private static function get_inner_xml($node)
|
||||||
{
|
{
|
||||||
/* Fetch as <some-node>content</some-node>, extract content. */
|
/* Fetch as <some-node>content</some-node>, extract content. */
|
||||||
|
|
||||||
$s = $node->asXML();
|
$s = $node->asXML();
|
||||||
$start = strpos($s, ">") + 1;
|
$start = strpos($s, ">") + 1;
|
||||||
$length = strlen($s) - $start - (3 + strlen($node->getName()));
|
$length = strlen($s) - $start - (3 + strlen($node->getName()));
|
||||||
$s = substr($s, $start, $length);
|
$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)
|
/**
|
||||||
{
|
* You can use the following syntax:
|
||||||
$input = $matches[1];
|
*
|
||||||
$arr = explode(":", $input);
|
* <a href="%OKAPI:docurl:fragment%">any text</a> - to reference fragment of introducing
|
||||||
$plugin_name = $arr[0];
|
* 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) {
|
switch ($plugin_name) {
|
||||||
case 'docurl':
|
case 'docurl':
|
||||||
$fragment = $arr[1];
|
$fragment = $arr[1];
|
||||||
return Settings::get('SITE_URL')."okapi/introduction.html#".$fragment;
|
return Settings::get('SITE_URL')."okapi/introduction.html#".$fragment;
|
||||||
default:
|
case 'methodref':
|
||||||
throw new Exception("Unknown plugin: ".$input);
|
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)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$methodname = $request->get_parameter('name');
|
$methodname = $request->get_parameter('name');
|
||||||
if (!$methodname)
|
if (!$methodname)
|
||||||
throw new ParamMissing('name');
|
throw new ParamMissing('name');
|
||||||
if (!preg_match("#^services/[0-9a-z_/]*$#", $methodname))
|
if (!preg_match("#^services/[0-9a-z_/]*$#", $methodname))
|
||||||
throw new InvalidParam('name');
|
throw new InvalidParam('name');
|
||||||
if (!OkapiServiceRunner::exists($methodname))
|
if (!OkapiServiceRunner::exists($methodname))
|
||||||
throw new InvalidParam('name', "Method does not exist: '$methodname'.");
|
throw new InvalidParam('name', "Method does not exist: '$methodname'.");
|
||||||
$options = OkapiServiceRunner::options($methodname);
|
$options = OkapiServiceRunner::options($methodname);
|
||||||
if (!isset($options['min_auth_level']))
|
if (!isset($options['min_auth_level']))
|
||||||
throw new Exception("Method $methodname is missing a required 'min_auth_level' option!");
|
throw new Exception("Method $methodname is missing a required 'min_auth_level' option!");
|
||||||
$docs = simplexml_load_string(OkapiServiceRunner::docs($methodname));
|
$docs = simplexml_load_string(OkapiServiceRunner::docs($methodname));
|
||||||
$exploded = explode("/", $methodname);
|
$exploded = explode("/", $methodname);
|
||||||
$result = array(
|
$result = array(
|
||||||
'name' => $methodname,
|
'name' => $methodname,
|
||||||
'short_name' => end($exploded),
|
'short_name' => end($exploded),
|
||||||
'ref_url' => Settings::get('SITE_URL')."okapi/$methodname.html",
|
'ref_url' => Settings::get('SITE_URL')."okapi/$methodname.html",
|
||||||
'auth_options' => array(
|
'auth_options' => array(
|
||||||
'min_auth_level' => $options['min_auth_level'],
|
'min_auth_level' => $options['min_auth_level'],
|
||||||
'oauth_consumer' => $options['min_auth_level'] >= 2,
|
'oauth_consumer' => $options['min_auth_level'] >= 2,
|
||||||
'oauth_token' => $options['min_auth_level'] >= 3,
|
'oauth_token' => $options['min_auth_level'] >= 3,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (!$docs->brief)
|
if (!$docs->brief)
|
||||||
throw new Exception("Missing <brief> element in the $methodname.xml file.");
|
throw new Exception("Missing <brief> element in the $methodname.xml file.");
|
||||||
if ($docs->brief != self::get_inner_xml($docs->brief))
|
if ($docs->brief != self::get_inner_xml($docs->brief))
|
||||||
throw new Exception("The <brief> element may not contain HTML markup ($methodname.xml).");
|
throw new Exception("The <brief> element may not contain HTML markup ($methodname.xml).");
|
||||||
if (strlen($docs->brief) > 80)
|
if (strlen($docs->brief) > 80)
|
||||||
throw new Exception("The <brief> description may not be longer than 80 characters ($methodname.xml).");
|
throw new Exception("The <brief> description may not be longer than 80 characters ($methodname.xml).");
|
||||||
if (strpos($docs->brief, "\n") !== false)
|
if (strpos($docs->brief, "\n") !== false)
|
||||||
throw new Exception("The <brief> element may not contain new-lines ($methodname.xml).");
|
throw new Exception("The <brief> element may not contain new-lines ($methodname.xml).");
|
||||||
if (substr(trim($docs->brief), -1) == '.')
|
if (substr(trim($docs->brief), -1) == '.')
|
||||||
throw new Exception("The <brief> element should not end with a dot ($methodname.xml).");
|
throw new Exception("The <brief> element should not end with a dot ($methodname.xml).");
|
||||||
$result['brief_description'] = self::get_inner_xml($docs->brief);
|
$result['brief_description'] = self::get_inner_xml($docs->brief);
|
||||||
if ($docs->{'issue-id'})
|
if ($docs->{'issue-id'})
|
||||||
$result['issue_id'] = (string)$docs->{'issue-id'};
|
$result['issue_id'] = (string)$docs->{'issue-id'};
|
||||||
else
|
else
|
||||||
$result['issue_id'] = null;
|
$result['issue_id'] = null;
|
||||||
if (!$docs->desc)
|
if (!$docs->desc)
|
||||||
throw new Exception("Missing <desc> element in the $methodname.xml file.");
|
throw new Exception("Missing <desc> element in the $methodname.xml file.");
|
||||||
$result['description'] = self::get_inner_xml($docs->desc);
|
$result['description'] = self::get_inner_xml($docs->desc);
|
||||||
$result['arguments'] = array();
|
$result['arguments'] = array();
|
||||||
foreach ($docs->req as $arg) { $result['arguments'][] = self::arg_desc($arg); }
|
foreach ($docs->req as $arg) { $result['arguments'][] = self::arg_desc($arg); }
|
||||||
foreach ($docs->opt 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)
|
foreach ($docs->{'import-params'} as $import_desc)
|
||||||
{
|
{
|
||||||
$attrs = $import_desc->attributes();
|
$attrs = $import_desc->attributes();
|
||||||
$referenced_methodname = $attrs['method'];
|
$referenced_methodname = $attrs['method'];
|
||||||
$referenced_method_info = OkapiServiceRunner::call('services/apiref/method',
|
$referenced_method_info = OkapiServiceRunner::call('services/apiref/method',
|
||||||
new OkapiInternalRequest(new OkapiInternalConsumer(), null, array('name' => $referenced_methodname)));
|
new OkapiInternalRequest(new OkapiInternalConsumer(), null, array('name' => $referenced_methodname)));
|
||||||
$include_list = isset($attrs['params']) ? explode("|", $attrs['params']) : null;
|
$include_list = isset($attrs['params']) ? explode("|", $attrs['params']) : null;
|
||||||
$exclude_list = isset($attrs['except']) ? explode("|", $attrs['except']) : array();
|
$exclude_list = isset($attrs['except']) ? explode("|", $attrs['except']) : array();
|
||||||
foreach ($referenced_method_info['arguments'] as $arg)
|
foreach ($referenced_method_info['arguments'] as $arg)
|
||||||
{
|
{
|
||||||
if ($arg['class'] == 'common-formatting')
|
if ($arg['class'] == 'common-formatting')
|
||||||
continue;
|
continue;
|
||||||
if (($include_list === null) && (count($exclude_list) == 0))
|
if (($include_list === null) && (count($exclude_list) == 0))
|
||||||
{
|
{
|
||||||
$arg['description'] = "<i>Inherited from <a href='".$referenced_method_info['ref_url'].
|
$arg['description'] = "<i>Inherited from <a href='".$referenced_method_info['ref_url'].
|
||||||
"'>".$referenced_method_info['name']."</a> method.</i>";
|
"'>".$referenced_method_info['name']."</a> method.</i>";
|
||||||
}
|
}
|
||||||
elseif (
|
elseif (
|
||||||
(($include_list === null) || in_array($arg['name'], $include_list))
|
(($include_list === null) || in_array($arg['name'], $include_list))
|
||||||
&& (!in_array($arg['name'], $exclude_list))
|
&& (!in_array($arg['name'], $exclude_list))
|
||||||
) {
|
) {
|
||||||
$arg['description'] = "<i>Same as in the <a href='".$referenced_method_info['ref_url'].
|
$arg['description'] = "<i>Same as in the <a href='".$referenced_method_info['ref_url'].
|
||||||
"'>".$referenced_method_info['name']."</a> method.</i>";
|
"'>".$referenced_method_info['name']."</a> method.</i>";
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$arg['class'] = 'inherited';
|
$arg['class'] = 'inherited';
|
||||||
$result['arguments'][] = $arg;
|
$result['arguments'][] = $arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($docs->{'common-format-params'})
|
if ($docs->{'common-format-params'})
|
||||||
{
|
{
|
||||||
$result['arguments'][] = array(
|
$result['arguments'][] = array(
|
||||||
'name' => 'format',
|
'name' => 'format',
|
||||||
'is_required' => false,
|
'is_required' => false,
|
||||||
'is_deprecated' => false,
|
'is_deprecated' => false,
|
||||||
'class' => 'common-formatting',
|
'class' => 'common-formatting',
|
||||||
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
|
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
|
||||||
);
|
);
|
||||||
$result['arguments'][] = array(
|
$result['arguments'][] = array(
|
||||||
'name' => 'callback',
|
'name' => 'callback',
|
||||||
'is_required' => false,
|
'is_required' => false,
|
||||||
'is_deprecated' => false,
|
'is_deprecated' => false,
|
||||||
'class' => 'common-formatting',
|
'class' => 'common-formatting',
|
||||||
'description' => "<i>Standard <a href='".Settings::get('SITE_URL')."okapi/introduction.html#common-formatting'>common formatting</a> argument.</i>"
|
'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)
|
foreach ($result['arguments'] as &$arg_ref)
|
||||||
if ($arg_ref['is_deprecated'])
|
if ($arg_ref['is_deprecated'])
|
||||||
$arg_ref['class'] .= " deprecated";
|
$arg_ref['class'] .= " deprecated";
|
||||||
if (!$docs->returns)
|
if (!$docs->returns)
|
||||||
throw new Exception("Missing <returns> element in the $methodname.xml file. ".
|
throw new Exception("Missing <returns> element in the $methodname.xml file. ".
|
||||||
"If your method does not return anything, you should document in nonetheless.");
|
"If your method does not return anything, you should document in nonetheless.");
|
||||||
$result['returns'] = self::get_inner_xml($docs->returns);
|
$result['returns'] = self::get_inner_xml($docs->returns);
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get information on a given OKAPI service method</brief>
|
<brief>Get information on a given OKAPI service method</brief>
|
||||||
<issue-id>13</issue-id>
|
<issue-id>13</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method allows you to <b>access API documentation</b> (the same which you
|
<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>
|
are reading just now). Given a method name, it returns a complete method description.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='name'>
|
<req name='name'>
|
||||||
Name of a method (begins with "services/").
|
Name of a method (begins with "services/").
|
||||||
</req>
|
</req>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>name</b> - name of the method,</li>
|
<li><b>name</b> - name of the method,</li>
|
||||||
<li><b>short_name</b> - name without a path,</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
|
<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
|
homepage Issue Tracker) associated with this method <b>or null</b> if this
|
||||||
method has associated issue,</li>
|
method has associated issue,</li>
|
||||||
<li><b>description</b> - HTML-formatted description of what the method does,</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,
|
<li><b>brief_description</b> - brief (max 80 characters), single-line,
|
||||||
plain-text description of what the method does,</li>
|
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>ref_url</b> - URL of the documentation page with method description,</li>
|
||||||
<li>
|
<li>
|
||||||
<b>auth_options</b> - a dictionary which describes authentication
|
<b>auth_options</b> - a dictionary which describes authentication
|
||||||
requirements for this method, it has a following structure:
|
requirements for this method, it has a following structure:
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>min_auth_level</b> - integer, in range from 0 to 3,
|
<li><b>min_auth_level</b> - integer, in range from 0 to 3,
|
||||||
see Introduction page.</li>
|
see Introduction page.</li>
|
||||||
<li><b>oauth_consumer</b> - true, if requests are required to be signed
|
<li><b>oauth_consumer</b> - true, if requests are required to be signed
|
||||||
with OAuth Consumer Key (min_auth_level >= 2),</li>
|
with OAuth Consumer Key (min_auth_level >= 2),</li>
|
||||||
<li><b>oauth_token</b> - true, if requests are required to include an
|
<li><b>oauth_token</b> - true, if requests are required to include an
|
||||||
OAuth Token (min_auth_level == 3).</li>
|
OAuth Token (min_auth_level == 3).</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><b>arguments</b> - list of dictionaries, describes method
|
<li><b>arguments</b> - list of dictionaries, describes method
|
||||||
arguments. Each dictionary has a following structure:
|
arguments. Each dictionary has a following structure:
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>name</b> - name of an argument,</li>
|
<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_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>is_deprecated</b> - boolean, true if the argument is deprecated,</li>
|
||||||
<li><b>description</b> - HTML-formatted description of an argument.</li>
|
<li><b>description</b> - HTML-formatted description of an argument.</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>class</b> - space separated list of the following values: <i>public</i>,
|
<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>
|
<i>inherited</i>, <i>common-formatting</i> and <i>deprecated</i>
|
||||||
(other values might be introduced in future).</p>
|
(other values might be introduced in future).</p>
|
||||||
<p>Currently these values do not mean anything specific. They are
|
<p>Currently these values do not mean anything specific. They are
|
||||||
used for different coloring/styling in the documentation pages.</p>
|
used for different coloring/styling in the documentation pages.</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><b>returns</b> - HTML-formatted description method's return value.</li>
|
<li><b>returns</b> - HTML-formatted description method's return value.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -15,33 +15,33 @@ use okapi\OkapiInternalRequest;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 0
|
'min_auth_level' => 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$methodnames = OkapiServiceRunner::$all_names;
|
$methodnames = OkapiServiceRunner::$all_names;
|
||||||
sort($methodnames);
|
sort($methodnames);
|
||||||
$cache_key = "api_ref/method_index#".md5(implode("#", $methodnames));
|
$cache_key = "api_ref/method_index#".md5(implode("#", $methodnames));
|
||||||
$results = Cache::get($cache_key);
|
$results = Cache::get($cache_key);
|
||||||
if ($results == null)
|
if ($results == null)
|
||||||
{
|
{
|
||||||
$results = array();
|
$results = array();
|
||||||
foreach ($methodnames as $methodname)
|
foreach ($methodnames as $methodname)
|
||||||
{
|
{
|
||||||
$info = OkapiServiceRunner::call('services/apiref/method', new OkapiInternalRequest(
|
$info = OkapiServiceRunner::call('services/apiref/method', new OkapiInternalRequest(
|
||||||
new OkapiInternalConsumer(), null, array('name' => $methodname)));
|
new OkapiInternalConsumer(), null, array('name' => $methodname)));
|
||||||
$results[] = array(
|
$results[] = array(
|
||||||
'name' => $info['name'],
|
'name' => $info['name'],
|
||||||
'brief_description' => $info['brief_description'],
|
'brief_description' => $info['brief_description'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Cache::set($cache_key, $results, 3600);
|
Cache::set($cache_key, $results, 3600);
|
||||||
}
|
}
|
||||||
return Okapi::formatted_response($request, $results);
|
return Okapi::formatted_response($request, $results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get a list of OKAPI methods with brief descriptions</brief>
|
<brief>Get a list of OKAPI methods with brief descriptions</brief>
|
||||||
<issue-id>12</issue-id>
|
<issue-id>12</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Get a list of OKAPI methods with brief descriptions.</p>
|
<p>Get a list of OKAPI methods with brief descriptions.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
A list of dictionaries, each of which contains one API
|
A list of dictionaries, each of which contains one API
|
||||||
method description in the following format:
|
method description in the following format:
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>name</b> - name of a method,</li>
|
<li><b>name</b> - name of a method,</li>
|
||||||
<li><b>brief_description</b> - brief (max 80 characters), single-line,
|
<li><b>brief_description</b> - brief (max 80 characters), single-line,
|
||||||
plain-text description of what the method does.</li>
|
plain-text description of what the method does.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -13,20 +13,20 @@ use okapi\OkapiInternalRequest;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 0
|
'min_auth_level' => 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$result = array();
|
$result = array();
|
||||||
$result['site_url'] = Settings::get('SITE_URL');
|
$result['site_url'] = Settings::get('SITE_URL');
|
||||||
$result['okapi_base_url'] = $result['site_url']."okapi/";
|
$result['okapi_base_url'] = $result['site_url']."okapi/";
|
||||||
$result['site_name'] = Okapi::get_normalized_site_name();
|
$result['site_name'] = Okapi::get_normalized_site_name();
|
||||||
$result['okapi_revision'] = Okapi::$revision;
|
$result['okapi_revision'] = Okapi::$revision;
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get information on this OKAPI installation</brief>
|
<brief>Get information on this OKAPI installation</brief>
|
||||||
<issue-id>14</issue-id>
|
<issue-id>14</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
Retrieve some basic information about this OKAPI installation.
|
Retrieve some basic information about this OKAPI installation.
|
||||||
</desc>
|
</desc>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<b>site_url</b> - URL of the Opencaching site which is running
|
<b>site_url</b> - URL of the Opencaching site which is running
|
||||||
the OKAPI installation (usually this looks like
|
the OKAPI installation (usually this looks like
|
||||||
"http://www.opencaching.<i>xx</i>/", where <b>xx</b> is a top
|
"http://www.opencaching.<i>xx</i>/", where <b>xx</b> is a top
|
||||||
level domain of a country).
|
level domain of a country).
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<b>okapi_base_url</b> - URL of the OKAPI installation (usually this is
|
<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
|
<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
|
that); this value is to be used as a prefix when constructing service
|
||||||
method URLs,
|
method URLs,
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<b>site_name</b> - international name of the Opencaching site,
|
<b>site_name</b> - international name of the Opencaching site,
|
||||||
</li>
|
</li>
|
||||||
<li><b>okapi_revision</b> - integer, an SVN revision of the OKAPI project
|
<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
|
installed on this Opencaching site, <b>or null</b>, when could not
|
||||||
determine revision number.</li>
|
determine revision number.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -15,104 +15,104 @@ use okapi\OkapiInternalRequest;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 0
|
'min_auth_level' => 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# The list of installations is periodically refreshed by contacting OKAPI
|
# The list of installations is periodically refreshed by contacting OKAPI
|
||||||
# repository. This method usually displays the cached version of it.
|
# repository. This method usually displays the cached version of it.
|
||||||
|
|
||||||
$cachekey = 'apisrv/installations';
|
$cachekey = 'apisrv/installations';
|
||||||
$backupkey = 'apisrv/installations-backup';
|
$backupkey = 'apisrv/installations-backup';
|
||||||
$results = Cache::get($cachekey);
|
$results = Cache::get($cachekey);
|
||||||
if (!$results)
|
if (!$results)
|
||||||
{
|
{
|
||||||
# Download the current list of OKAPI servers.
|
# Download the current list of OKAPI servers.
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$opts = array(
|
$opts = array(
|
||||||
'http' => array(
|
'http' => array(
|
||||||
'method' => "GET",
|
'method' => "GET",
|
||||||
'timeout' => 5.0
|
'timeout' => 5.0
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$context = stream_context_create($opts);
|
$context = stream_context_create($opts);
|
||||||
$xml = file_get_contents("http://opencaching-api.googlecode.com/svn/trunk/etc/installations.xml",
|
$xml = file_get_contents("http://opencaching-api.googlecode.com/svn/trunk/etc/installations.xml",
|
||||||
false, $context);
|
false, $context);
|
||||||
}
|
}
|
||||||
catch (ErrorException $e)
|
catch (ErrorException $e)
|
||||||
{
|
{
|
||||||
# Google failed on us. Try to respond with a backup list.
|
# Google failed on us. Try to respond with a backup list.
|
||||||
|
|
||||||
$results = Cache::get($backupkey);
|
$results = Cache::get($backupkey);
|
||||||
if ($results)
|
if ($results)
|
||||||
{
|
{
|
||||||
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
||||||
return Okapi::formatted_response($request, $results);
|
return Okapi::formatted_response($request, $results);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Backup has expired (or have never been cached). If we're on a development
|
# 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.
|
# server then probably it's okay. In production this SHOULD NOT happen.
|
||||||
|
|
||||||
$results = array(
|
$results = array(
|
||||||
array(
|
array(
|
||||||
'site_url' => Settings::get('SITE_URL'),
|
'site_url' => Settings::get('SITE_URL'),
|
||||||
'site_name' => "Unable to retrieve!",
|
'site_name' => "Unable to retrieve!",
|
||||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
||||||
return Okapi::formatted_response($request, $results);
|
return Okapi::formatted_response($request, $results);
|
||||||
}
|
}
|
||||||
|
|
||||||
$doc = simplexml_load_string($xml);
|
$doc = simplexml_load_string($xml);
|
||||||
$results = array();
|
$results = array();
|
||||||
$i_was_included = false;
|
$i_was_included = false;
|
||||||
foreach ($doc->installation as $inst)
|
foreach ($doc->installation as $inst)
|
||||||
{
|
{
|
||||||
$site_url = (string)$inst[0]['site_url'];
|
$site_url = (string)$inst[0]['site_url'];
|
||||||
if ($inst[0]['okapi_base_url'])
|
if ($inst[0]['okapi_base_url'])
|
||||||
$okapi_base_url = (string)$inst[0]['okapi_base_url'];
|
$okapi_base_url = (string)$inst[0]['okapi_base_url'];
|
||||||
else
|
else
|
||||||
$okapi_base_url = $site_url."okapi/";
|
$okapi_base_url = $site_url."okapi/";
|
||||||
if ($inst[0]['site_name'])
|
if ($inst[0]['site_name'])
|
||||||
$site_name = (string)$inst[0]['site_name'];
|
$site_name = (string)$inst[0]['site_name'];
|
||||||
else
|
else
|
||||||
$site_name = Okapi::get_normalized_site_name($site_url);
|
$site_name = Okapi::get_normalized_site_name($site_url);
|
||||||
$results[] = array(
|
$results[] = array(
|
||||||
'site_url' => $site_url,
|
'site_url' => $site_url,
|
||||||
'site_name' => $site_name,
|
'site_name' => $site_name,
|
||||||
'okapi_base_url' => $okapi_base_url,
|
'okapi_base_url' => $okapi_base_url,
|
||||||
);
|
);
|
||||||
if ($site_url == Settings::get('SITE_URL'))
|
if ($site_url == Settings::get('SITE_URL'))
|
||||||
$i_was_included = true;
|
$i_was_included = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
# If running on a local development installation, then include the local
|
# If running on a local development installation, then include the local
|
||||||
# installation URL.
|
# installation URL.
|
||||||
|
|
||||||
if (!$i_was_included)
|
if (!$i_was_included)
|
||||||
{
|
{
|
||||||
$results[] = array(
|
$results[] = array(
|
||||||
'site_url' => Settings::get('SITE_URL'),
|
'site_url' => Settings::get('SITE_URL'),
|
||||||
'site_name' => "DEVELSITE",
|
'site_name' => "DEVELSITE",
|
||||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||||
);
|
);
|
||||||
# Contact OKAPI developers in order to get added to the official sites list!
|
# 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($cachekey, $results, 86400);
|
||||||
Cache::set($backupkey, $results, 86400*30);
|
Cache::set($backupkey, $results, 86400*30);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Okapi::formatted_response($request, $results);
|
return Okapi::formatted_response($request, $results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get the list of all public OKAPI installations</brief>
|
<brief>Get the list of all public OKAPI installations</brief>
|
||||||
<issue-id>39</issue-id>
|
<issue-id>39</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
Get the list of all public OKAPI installations. Keep in mind that
|
Get the list of all public OKAPI installations. Keep in mind that
|
||||||
OKAPI installations might differ slightly. If you plan on using
|
OKAPI installations might differ slightly. If you plan on using
|
||||||
multiple OKAPI installations in your application (which is a very
|
multiple OKAPI installations in your application (which is a very
|
||||||
good thing!) you should test it against the one with the <b>lowest</b>
|
good thing!) you should test it against the one with the <b>lowest</b>
|
||||||
OKAPI revision number.
|
OKAPI revision number.
|
||||||
</desc>
|
</desc>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<b>site_url</b> - URL of the Opencaching site which is running
|
<b>site_url</b> - URL of the Opencaching site which is running
|
||||||
the OKAPI installation (usually this looks like
|
the OKAPI installation (usually this looks like
|
||||||
"http://www.opencaching.<i>xx</i>/", where <b>xx</b> is a top
|
"http://www.opencaching.<i>xx</i>/", where <b>xx</b> is a top
|
||||||
level domain of a country).
|
level domain of a country).
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<b>site_name</b> - universal name for this site (should be fine
|
<b>site_name</b> - universal name for this site (should be fine
|
||||||
for all languages),
|
for all languages),
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<b>okapi_base_url</b> - URL of the OKAPI installation (usually this is
|
<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
|
<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
|
that); this value is to be used as a prefix when constructing service
|
||||||
method URLs.
|
method URLs.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -15,48 +15,48 @@ use okapi\Settings;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 0
|
'min_auth_level' => 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$cachekey = "apisrv/stats";
|
$cachekey = "apisrv/stats";
|
||||||
$result = Cache::get($cachekey);
|
$result = Cache::get($cachekey);
|
||||||
if (!$result)
|
if (!$result)
|
||||||
{
|
{
|
||||||
$result = array(
|
$result = array(
|
||||||
'cache_count' => 0 + Db::select_value("
|
'cache_count' => 0 + Db::select_value("
|
||||||
select count(*) from caches where status in (1,2,3)
|
select count(*) from caches where status in (1,2,3)
|
||||||
"),
|
"),
|
||||||
'user_count' => 0 + Db::select_value("
|
'user_count' => 0 + Db::select_value("
|
||||||
select count(*) from (
|
select count(*) from (
|
||||||
select distinct user_id
|
select distinct user_id
|
||||||
from cache_logs
|
from cache_logs
|
||||||
where
|
where
|
||||||
type in (1,2)
|
type in (1,2)
|
||||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||||
UNION DISTINCT
|
UNION DISTINCT
|
||||||
select distinct user_id
|
select distinct user_id
|
||||||
from caches
|
from caches
|
||||||
) as t;
|
) as t;
|
||||||
"),
|
"),
|
||||||
'apps_count' => 0 + Db::select_value("select count(*) from okapi_consumers;"),
|
'apps_count' => 0 + Db::select_value("select count(*) from okapi_consumers;"),
|
||||||
'apps_active' => 0 + Db::select_value("
|
'apps_active' => 0 + Db::select_value("
|
||||||
select count(distinct s.consumer_key)
|
select count(distinct s.consumer_key)
|
||||||
from
|
from
|
||||||
okapi_stats_hourly s,
|
okapi_stats_hourly s,
|
||||||
okapi_consumers c
|
okapi_consumers c
|
||||||
where
|
where
|
||||||
s.consumer_key = c.`key`
|
s.consumer_key = c.`key`
|
||||||
and s.period_start > date_add(now(), interval -30 day)
|
and s.period_start > date_add(now(), interval -30 day)
|
||||||
"),
|
"),
|
||||||
);
|
);
|
||||||
Cache::set($cachekey, $result, 86400); # cache it for one day
|
Cache::set($cachekey, $result, 86400); # cache it for one day
|
||||||
}
|
}
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get some basic stats about the site</brief>
|
<brief>Get some basic stats about the site</brief>
|
||||||
<issue-id>43</issue-id>
|
<issue-id>43</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
Retrieve some basic statistics about this OKAPI installation.
|
Retrieve some basic statistics about this OKAPI installation.
|
||||||
If you want some more stats, post a comment!
|
If you want some more stats, post a comment!
|
||||||
</desc>
|
</desc>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>cache_count</b> - approximate total number of geocaches stored at this site,</li>
|
<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>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
|
<li><b>apps_count</b> - approximate total number of all OKAPI applications (number of
|
||||||
registered API Keys).</li>
|
registered API Keys).</li>
|
||||||
<li><b>apps_active</b> - approximate number of active OKAPI applications (the ones which issued
|
<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>
|
at least one, non-anonymous OKAPI request during the last month).</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -18,272 +18,272 @@ use SimpleXMLElement;
|
|||||||
|
|
||||||
class AttrHelper
|
class AttrHelper
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* By default, when DEBUG mode is enabled, the attributes.xml file is
|
* 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
|
* reloaded practically on every request. If you don't want that, you can
|
||||||
* temporarilly disable this behavior by settings this to false.
|
* temporarilly disable this behavior by settings this to false.
|
||||||
*/
|
*/
|
||||||
private static $RELOAD_ON_DEBUG = true;
|
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
|
* 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
|
* In order for the $RELOAD_ON_DEBUG to work properly when switching to/from
|
||||||
* DEBUG mode.
|
* DEBUG mode.
|
||||||
*/
|
*/
|
||||||
private static function cache_key_suffix()
|
private static function cache_key_suffix()
|
||||||
{
|
{
|
||||||
return (self::$RELOAD_ON_DEBUG) ? "#DBG" : "";
|
return (self::$RELOAD_ON_DEBUG) ? "#DBG" : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the timeout to be used for attribute caching. */
|
/** Return the timeout to be used for attribute caching. */
|
||||||
private static function ttl()
|
private static function ttl()
|
||||||
{
|
{
|
||||||
return (Settings::get('DEBUG') && self::$RELOAD_ON_DEBUG) ? 2 : 86400;
|
return (Settings::get('DEBUG') && self::$RELOAD_ON_DEBUG) ? 2 : 86400;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces an immediate refresh of the current attributes from the
|
* Forces an immediate refresh of the current attributes from the
|
||||||
* attribute-definitions.xml file.
|
* attribute-definitions.xml file.
|
||||||
*/
|
*/
|
||||||
public static function refresh_now()
|
public static function refresh_now()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$path = $GLOBALS['rootpath']."okapi/services/attrs/attribute-definitions.xml";
|
$path = $GLOBALS['rootpath']."okapi/services/attrs/attribute-definitions.xml";
|
||||||
$xml = file_get_contents($path);
|
$xml = file_get_contents($path);
|
||||||
self::refresh_from_string($xml);
|
self::refresh_from_string($xml);
|
||||||
}
|
}
|
||||||
catch (Exception $e)
|
catch (Exception $e)
|
||||||
{
|
{
|
||||||
# Failed to read or parse the file (i.e. after a syntax error was
|
# Failed to read or parse the file (i.e. after a syntax error was
|
||||||
# commited). Let's check when the last successful parse occured.
|
# 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)
|
if (self::$attr_dict === null)
|
||||||
{
|
{
|
||||||
# That's bad! We don't have ANY copy of the data AND we failed
|
# 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.
|
# to parse it. We will use a fake, empty data.
|
||||||
|
|
||||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||||
$cachedvalue = array(
|
$cachedvalue = array(
|
||||||
'attr_dict' => array(),
|
'attr_dict' => array(),
|
||||||
);
|
);
|
||||||
Cache::set($cache_key, $cachedvalue, self::ttl());
|
Cache::set($cache_key, $cachedvalue, self::ttl());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh all attributes from the given XML. Usually, this file is
|
* Refresh all attributes from the given XML. Usually, this file is
|
||||||
* downloaded from Google Code (using refresh_now).
|
* downloaded from Google Code (using refresh_now).
|
||||||
*/
|
*/
|
||||||
public static function refresh_from_string($xml)
|
public static function refresh_from_string($xml)
|
||||||
{
|
{
|
||||||
/* The attribute-definitions.xml file defines relationships between
|
/* The attribute-definitions.xml file defines relationships between
|
||||||
* attributes originating from various OC installations. Each
|
* attributes originating from various OC installations. Each
|
||||||
* installation uses internal IDs of its own. Which "attribute schema"
|
* installation uses internal IDs of its own. Which "attribute schema"
|
||||||
* is being used in THIS installation? */
|
* is being used in THIS installation? */
|
||||||
|
|
||||||
$my_schema = Settings::get('ORIGIN_URL');
|
$my_schema = Settings::get('ORIGIN_URL');
|
||||||
|
|
||||||
$doc = simplexml_load_string($xml);
|
$doc = simplexml_load_string($xml);
|
||||||
$cachedvalue = array(
|
$cachedvalue = array(
|
||||||
'attr_dict' => array(),
|
'attr_dict' => array(),
|
||||||
);
|
);
|
||||||
|
|
||||||
# Build cache attributes dictionary
|
# Build cache attributes dictionary
|
||||||
|
|
||||||
$all_internal_ids = array();
|
$all_internal_ids = array();
|
||||||
foreach ($doc->attr as $attrnode)
|
foreach ($doc->attr as $attrnode)
|
||||||
{
|
{
|
||||||
$attr = array(
|
$attr = array(
|
||||||
'acode' => (string)$attrnode['acode'],
|
'acode' => (string)$attrnode['acode'],
|
||||||
'gc_equivs' => array(),
|
'gc_equivs' => array(),
|
||||||
'internal_id' => null,
|
'internal_id' => null,
|
||||||
'names' => array(),
|
'names' => array(),
|
||||||
'descriptions' => array(),
|
'descriptions' => array(),
|
||||||
'is_discontinued' => true
|
'is_discontinued' => true
|
||||||
);
|
);
|
||||||
foreach ($attrnode->groundspeak as $gsnode)
|
foreach ($attrnode->groundspeak as $gsnode)
|
||||||
{
|
{
|
||||||
$attr['gc_equivs'][] = array(
|
$attr['gc_equivs'][] = array(
|
||||||
'id' => (int)$gsnode['id'],
|
'id' => (int)$gsnode['id'],
|
||||||
'inc' => in_array((string)$gsnode['inc'], array("true", "1")) ? 1 : 0,
|
'inc' => in_array((string)$gsnode['inc'], array("true", "1")) ? 1 : 0,
|
||||||
'name' => (string)$gsnode['name']
|
'name' => (string)$gsnode['name']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
foreach ($attrnode->opencaching as $ocnode)
|
foreach ($attrnode->opencaching as $ocnode)
|
||||||
{
|
{
|
||||||
/* If it is used by at least one OC node, then it's NOT discontinued. */
|
/* If it is used by at least one OC node, then it's NOT discontinued. */
|
||||||
$attr['is_discontinued'] = false;
|
$attr['is_discontinued'] = false;
|
||||||
|
|
||||||
if ((string)$ocnode['schema'] == $my_schema)
|
if ((string)$ocnode['schema'] == $my_schema)
|
||||||
{
|
{
|
||||||
/* It is used by THIS OC node. */
|
/* It is used by THIS OC node. */
|
||||||
|
|
||||||
$internal_id = (int)$ocnode['id'];
|
$internal_id = (int)$ocnode['id'];
|
||||||
if (isset($all_internal_ids[$internal_id]))
|
if (isset($all_internal_ids[$internal_id]))
|
||||||
throw new Exception("The internal attribute ".$internal_id.
|
throw new Exception("The internal attribute ".$internal_id.
|
||||||
" has multiple assigments to OKAPI attributes.");
|
" has multiple assigments to OKAPI attributes.");
|
||||||
$all_internal_ids[$internal_id] = true;
|
$all_internal_ids[$internal_id] = true;
|
||||||
if (!is_null($attr['internal_id']))
|
if (!is_null($attr['internal_id']))
|
||||||
throw new Exception("There are multiple internal IDs for the ".
|
throw new Exception("There are multiple internal IDs for the ".
|
||||||
$attr['acode']." attribute.");
|
$attr['acode']." attribute.");
|
||||||
$attr['internal_id'] = $internal_id;
|
$attr['internal_id'] = $internal_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($attrnode->lang as $langnode)
|
foreach ($attrnode->lang as $langnode)
|
||||||
{
|
{
|
||||||
$lang = (string)$langnode['id'];
|
$lang = (string)$langnode['id'];
|
||||||
foreach ($langnode->name as $namenode)
|
foreach ($langnode->name as $namenode)
|
||||||
{
|
{
|
||||||
if (isset($attr['names'][$lang]))
|
if (isset($attr['names'][$lang]))
|
||||||
throw new Exception("Duplicate ".$lang." name of attribute ".$attr['acode']);
|
throw new Exception("Duplicate ".$lang." name of attribute ".$attr['acode']);
|
||||||
$attr['names'][$lang] = (string)$namenode;
|
$attr['names'][$lang] = (string)$namenode;
|
||||||
}
|
}
|
||||||
foreach ($langnode->desc as $descnode)
|
foreach ($langnode->desc as $descnode)
|
||||||
{
|
{
|
||||||
if (isset($attr['descriptions'][$lang]))
|
if (isset($attr['descriptions'][$lang]))
|
||||||
throw new Exception("Duplicate ".$lang." description of attribute ".$attr['acode']);
|
throw new Exception("Duplicate ".$lang." description of attribute ".$attr['acode']);
|
||||||
$xml = $descnode->asxml(); /* contains "<desc>" and "</desc>" */
|
$xml = $descnode->asxml(); /* contains "<desc>" and "</desc>" */
|
||||||
$innerxml = preg_replace("/(^[^>]+>)|(<[^<]+$)/us", "", $xml);
|
$innerxml = preg_replace("/(^[^>]+>)|(<[^<]+$)/us", "", $xml);
|
||||||
$attr['descriptions'][$lang] = self::cleanup_string($innerxml);
|
$attr['descriptions'][$lang] = self::cleanup_string($innerxml);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$cachedvalue['attr_dict'][$attr['acode']] = $attr;
|
$cachedvalue['attr_dict'][$attr['acode']] = $attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||||
Cache::set($cache_key, $cachedvalue, self::ttl());
|
Cache::set($cache_key, $cachedvalue, self::ttl());
|
||||||
self::$attr_dict = $cachedvalue['attr_dict'];
|
self::$attr_dict = $cachedvalue['attr_dict'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object to be used for forward-compatibility (see the attributes method).
|
* Object to be used for forward-compatibility (see the attributes method).
|
||||||
*/
|
*/
|
||||||
public static function get_unknown_placeholder($acode)
|
public static function get_unknown_placeholder($acode)
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'acode' => $acode,
|
'acode' => $acode,
|
||||||
'gc_equivs' => array(),
|
'gc_equivs' => array(),
|
||||||
'internal_id' => null,
|
'internal_id' => null,
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'en' => "Unknown attribute"
|
'en' => "Unknown attribute"
|
||||||
),
|
),
|
||||||
'descriptions' => array(
|
'descriptions' => array(
|
||||||
'en' => (
|
'en' => (
|
||||||
"This attribute ($acode) is unknown at ".Okapi::get_normalized_site_name().
|
"This attribute ($acode) is unknown at ".Okapi::get_normalized_site_name().
|
||||||
". It might not exist, or it may be a new attribute, recognized ".
|
". It might not exist, or it may be a new attribute, recognized ".
|
||||||
"only in newer OKAPI installations. Perhaps ".Okapi::get_normalized_site_name().
|
"only in newer OKAPI installations. Perhaps ".Okapi::get_normalized_site_name().
|
||||||
" needs to have its OKAPI updated?"
|
" needs to have its OKAPI updated?"
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
'is_discontinued' => true
|
'is_discontinued' => true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize all the internal attributes (if not yet initialized). This
|
* Initialize all the internal attributes (if not yet initialized). This
|
||||||
* loads attribute values from the cache. If they are not present in the
|
* 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.
|
* cache, it will read and parse them from attribute-definitions.xml file.
|
||||||
*/
|
*/
|
||||||
private static function init_from_cache($allow_refreshing=true)
|
private static function init_from_cache($allow_refreshing=true)
|
||||||
{
|
{
|
||||||
if (self::$attr_dict !== null)
|
if (self::$attr_dict !== null)
|
||||||
{
|
{
|
||||||
/* Already initialized. */
|
/* Already initialized. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
$cache_key = "attrhelper/dict#".Okapi::$revision.self::cache_key_suffix();
|
||||||
$cachedvalue = Cache::get($cache_key);
|
$cachedvalue = Cache::get($cache_key);
|
||||||
if ($cachedvalue === null)
|
if ($cachedvalue === null)
|
||||||
{
|
{
|
||||||
# I.e. after Okapi::$revision is changed, or cache got invalidated.
|
# I.e. after Okapi::$revision is changed, or cache got invalidated.
|
||||||
|
|
||||||
if ($allow_refreshing)
|
if ($allow_refreshing)
|
||||||
{
|
{
|
||||||
self::refresh_now();
|
self::refresh_now();
|
||||||
self::init_from_cache(false);
|
self::init_from_cache(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$cachedvalue = array(
|
$cachedvalue = array(
|
||||||
'attr_dict' => array(),
|
'attr_dict' => array(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self::$attr_dict = $cachedvalue['attr_dict'];
|
self::$attr_dict = $cachedvalue['attr_dict'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a dictionary of all attributes. The format is INTERNAL and PRIVATE,
|
* 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).
|
* it is NOT the same as in the "attributes" method (but it is quite similar).
|
||||||
*/
|
*/
|
||||||
public static function get_attrdict()
|
public static function get_attrdict()
|
||||||
{
|
{
|
||||||
self::init_from_cache();
|
self::init_from_cache();
|
||||||
return self::$attr_dict;
|
return self::$attr_dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** "\n\t\tBla blabla\n\t\t<b>bla</b>bla.\n\t" => "Bla blabla <b>bla</b>bla." */
|
/** "\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)
|
private static function cleanup_string($s)
|
||||||
{
|
{
|
||||||
return preg_replace('/(^\s+)|(\s+$)/us', "", preg_replace('/\s+/us', " ", $s));
|
return preg_replace('/(^\s+)|(\s+$)/us', "", preg_replace('/\s+/us', " ", $s));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mapping table between internal attribute id => OKAPI A-code.
|
* Get the mapping table between internal attribute id => OKAPI A-code.
|
||||||
* The result is cached!
|
* The result is cached!
|
||||||
*/
|
*/
|
||||||
public static function get_internal_id_to_acode_mapping()
|
public static function get_internal_id_to_acode_mapping()
|
||||||
{
|
{
|
||||||
static $mapping = null;
|
static $mapping = null;
|
||||||
if ($mapping !== null)
|
if ($mapping !== null)
|
||||||
return $mapping;
|
return $mapping;
|
||||||
|
|
||||||
$cache_key = "attrhelper/id2acode/".Okapi::$revision.self::cache_key_suffix();
|
$cache_key = "attrhelper/id2acode/".Okapi::$revision.self::cache_key_suffix();
|
||||||
$mapping = Cache::get($cache_key);
|
$mapping = Cache::get($cache_key);
|
||||||
if (!$mapping)
|
if (!$mapping)
|
||||||
{
|
{
|
||||||
self::init_from_cache();
|
self::init_from_cache();
|
||||||
$mapping = array();
|
$mapping = array();
|
||||||
foreach (self::$attr_dict as $acode => &$attr_ref)
|
foreach (self::$attr_dict as $acode => &$attr_ref)
|
||||||
$mapping[$attr_ref['internal_id']] = $acode;
|
$mapping[$attr_ref['internal_id']] = $acode;
|
||||||
Cache::set($cache_key, $mapping, self::ttl());
|
Cache::set($cache_key, $mapping, self::ttl());
|
||||||
}
|
}
|
||||||
return $mapping;
|
return $mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mapping: A-codes => attribute name. The language for the name
|
* Get the mapping: A-codes => attribute name. The language for the name
|
||||||
* is selected based on the $langpref parameter. The result is cached!
|
* is selected based on the $langpref parameter. The result is cached!
|
||||||
*/
|
*/
|
||||||
public static function get_acode_to_name_mapping($langpref)
|
public static function get_acode_to_name_mapping($langpref)
|
||||||
{
|
{
|
||||||
static $mapping = null;
|
static $mapping = null;
|
||||||
if ($mapping !== null)
|
if ($mapping !== null)
|
||||||
return $mapping;
|
return $mapping;
|
||||||
|
|
||||||
$cache_key = md5(serialize(array("attrhelper/acode2name", $langpref,
|
$cache_key = md5(serialize(array("attrhelper/acode2name", $langpref,
|
||||||
Okapi::$revision, self::cache_key_suffix())));
|
Okapi::$revision, self::cache_key_suffix())));
|
||||||
$mapping = Cache::get($cache_key);
|
$mapping = Cache::get($cache_key);
|
||||||
if (!$mapping)
|
if (!$mapping)
|
||||||
{
|
{
|
||||||
self::init_from_cache();
|
self::init_from_cache();
|
||||||
$mapping = array();
|
$mapping = array();
|
||||||
foreach (self::$attr_dict as $acode => &$attr_ref)
|
foreach (self::$attr_dict as $acode => &$attr_ref)
|
||||||
{
|
{
|
||||||
$mapping[$acode] = Okapi::pick_best_language(
|
$mapping[$acode] = Okapi::pick_best_language(
|
||||||
$attr_ref['names'], $langpref);
|
$attr_ref['names'], $langpref);
|
||||||
}
|
}
|
||||||
Cache::set($cache_key, $mapping, self::ttl());
|
Cache::set($cache_key, $mapping, self::ttl());
|
||||||
}
|
}
|
||||||
return $mapping;
|
return $mapping;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,45 +17,45 @@ use okapi\services\attrs\AttrHelper;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# Read the parameters.
|
# Read the parameters.
|
||||||
|
|
||||||
$acode = $request->get_parameter('acode');
|
$acode = $request->get_parameter('acode');
|
||||||
if ($acode === null) throw new ParamMissing('acode');
|
if ($acode === null) throw new ParamMissing('acode');
|
||||||
|
|
||||||
$langpref = $request->get_parameter('langpref');
|
$langpref = $request->get_parameter('langpref');
|
||||||
if (!$langpref) $langpref = "en";
|
if (!$langpref) $langpref = "en";
|
||||||
|
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields) $fields = "name";
|
if (!$fields) $fields = "name";
|
||||||
|
|
||||||
$forward_compatible = $request->get_parameter('forward_compatible');
|
$forward_compatible = $request->get_parameter('forward_compatible');
|
||||||
if (!$forward_compatible) $forward_compatible = "true";
|
if (!$forward_compatible) $forward_compatible = "true";
|
||||||
|
|
||||||
# Pass them all to the attributes method.
|
# Pass them all to the attributes method.
|
||||||
|
|
||||||
$params = array(
|
$params = array(
|
||||||
'acodes' => $acode,
|
'acodes' => $acode,
|
||||||
'langpref' => $langpref,
|
'langpref' => $langpref,
|
||||||
'fields' => $fields,
|
'fields' => $fields,
|
||||||
'forward_compatible' => $forward_compatible
|
'forward_compatible' => $forward_compatible
|
||||||
);
|
);
|
||||||
$results = OkapiServiceRunner::call('services/attrs/attributes',
|
$results = OkapiServiceRunner::call('services/attrs/attributes',
|
||||||
new OkapiInternalRequest($request->consumer, $request->token, $params));
|
new OkapiInternalRequest($request->consumer, $request->token, $params));
|
||||||
$result = $results[$acode];
|
$result = $results[$acode];
|
||||||
if ($result === null)
|
if ($result === null)
|
||||||
{
|
{
|
||||||
/* Note, this can happen only when $forward_compatible is false. */
|
/* Note, this can happen only when $forward_compatible is false. */
|
||||||
throw new InvalidParam('acode', "Unknown A-code.");
|
throw new InvalidParam('acode', "Unknown A-code.");
|
||||||
}
|
}
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,134 +1,134 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve data on a single attribute</brief>
|
<brief>Retrieve data on a single attribute</brief>
|
||||||
<issue-id>268</issue-id>
|
<issue-id>268</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Retrieve data on a single OKAPI geocache-attribute.</p>
|
<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>.
|
<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
|
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
|
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.
|
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
|
Some attributes may get discontinued in the future, but they will remain accessible
|
||||||
by their original A-code.</p>
|
by their original A-code.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='acode'>
|
<req name='acode'>
|
||||||
The A-code of the attribute you're interested in.
|
The A-code of the attribute you're interested in.
|
||||||
</req>
|
</req>
|
||||||
<opt name='langpref' default='en'>
|
<opt name='langpref' default='en'>
|
||||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
<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
|
order of preference in which language will be chosen for fields like
|
||||||
<b>name</b> and <b>description</b>.</p>
|
<b>name</b> and <b>description</b>.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='fields' default='name'>
|
<opt name='fields' default='name'>
|
||||||
<p>Pipe-separated list of field names which you are interested with.
|
<p>Pipe-separated list of field names which you are interested with.
|
||||||
See below for the list of available fields.</p>
|
See below for the list of available fields.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='forward_compatible' default='true'>
|
<opt name='forward_compatible' default='true'>
|
||||||
By default, OKAPI will return an empty placeholder if you ask for an
|
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
|
unknown attribute. If you'd like to catch such errors and handle them
|
||||||
differently, then you may change this behavior by setting this parameter
|
differently, then you may change this behavior by setting this parameter
|
||||||
to <b>false</b>. Then, OKAPI will return HTTP 400 error response,
|
to <b>false</b>. Then, OKAPI will return HTTP 400 error response,
|
||||||
instead of the placeholder (note that it behaves differently in the
|
instead of the placeholder (note that it behaves differently in the
|
||||||
<b>attributes</b> method).
|
<b>attributes</b> method).
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of fields you have selected in the <b>fields</b>
|
<p>A dictionary of fields you have selected in the <b>fields</b>
|
||||||
parameter. Available fields:</p>
|
parameter. Available fields:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p><b>acode</b> - string, the A-code. Unique identifier of the
|
<p><b>acode</b> - string, the A-code. Unique identifier of the
|
||||||
attribute.</p>
|
attribute.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>name</b> - plaintext string, name of the attribute (language is
|
<p><b>name</b> - plaintext string, name of the attribute (language is
|
||||||
selected based on your <b>langpref</b> parameter),</p>
|
selected based on your <b>langpref</b> parameter),</p>
|
||||||
|
|
||||||
<p>If you think your language is missing, then feel free to add missing
|
<p>If you think your language is missing, then feel free to add missing
|
||||||
translations directly to OKAPI repository. See
|
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>
|
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>names</b> - a dictionary of all known names of the attribute, in
|
<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
|
various languages (ISO 639-1 language code is used as dictionary
|
||||||
key).</p>
|
key).</p>
|
||||||
|
|
||||||
<p>If you think your language is missing, then feel free to add missing
|
<p>If you think your language is missing, then feel free to add missing
|
||||||
translations directly to OKAPI repository. See
|
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>
|
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<b>description</b> - HTML string, description of the attribute (language is
|
<b>description</b> - HTML string, description of the attribute (language is
|
||||||
selected based on your <b>langpref</b> parameter),
|
selected based on your <b>langpref</b> parameter),
|
||||||
|
|
||||||
<p>If you think your language is missing, then feel free to add missing
|
<p>If you think your language is missing, then feel free to add missing
|
||||||
translations directly to OKAPI repository. See
|
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>
|
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>descriptions</b> - a dictionary of all known descriptions of the
|
<p><b>descriptions</b> - a dictionary of all known descriptions of the
|
||||||
attribute, in various languages (ISO 639-1 language code is used as
|
attribute, in various languages (ISO 639-1 language code is used as
|
||||||
dictionary key).</p>
|
dictionary key).</p>
|
||||||
|
|
||||||
<p>If you think your language is missing, then feel free to add missing
|
<p>If you think your language is missing, then feel free to add missing
|
||||||
translations directly to OKAPI repository. See
|
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>
|
<a href='https://code.google.com/p/opencaching-api/source/browse/trunk/okapi/services/attrs/attribute-definitions.xml'>here</a>.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>gc_equivs</b> - a list of Geocaching.com (Groundspeak)
|
<p><b>gc_equivs</b> - a list of Geocaching.com (Groundspeak)
|
||||||
attributes, which have exactly the same (or a very similar) meaning. Each
|
attributes, which have exactly the same (or a very similar) meaning. Each
|
||||||
attribute is described as a dictionary of the following structure:</p>
|
attribute is described as a dictionary of the following structure:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>id</b> - ID of the Geocaching.com attribute,</li>
|
<li><b>id</b> - ID of the Geocaching.com attribute,</li>
|
||||||
<li>
|
<li>
|
||||||
<b>inc</b> - integer, either 1 or 0. See Geocaching.com's
|
<b>inc</b> - integer, either 1 or 0. See Geocaching.com's
|
||||||
XSD for details on its meaning,
|
XSD for details on its meaning,
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<b>name</b> - the name of the attribute (as it is included
|
<b>name</b> - the name of the attribute (as it is included
|
||||||
in Geocaching.com GPX files).
|
in Geocaching.com GPX files).
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Note that one gc_equivs list may have multiple items on it, and
|
<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>
|
that one Geocaching.com ID may be present in many gc_equivs.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>is_locally_used</b> - boolean, indicates if the attribute is <i>currently</i>
|
<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>
|
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
|
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>
|
of the <b>geocache</b> method in this OKAPI installation.</p>
|
||||||
|
|
||||||
<p>Note that this flag can change in time. Some attributes may get
|
<p>Note that this flag can change in time. Some attributes may get
|
||||||
introduced into other installations, whereas other attributes may
|
introduced into other installations, whereas other attributes may
|
||||||
(temporarily or permanently) stop being used. In general, we are aiming
|
(temporarily or permanently) stop being used. In general, we are aiming
|
||||||
towards global unification of all attributes between all OC nodes,
|
towards global unification of all attributes between all OC nodes,
|
||||||
but this process will take time (and probably it will never
|
but this process will take time (and probably it will never
|
||||||
be 100% complete).</p>
|
be 100% complete).</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>local_icon_url</b> - an URL pointing to an image associated with
|
<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
|
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>
|
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
|
<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.
|
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
|
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>
|
prepared to receive <b>null</b>, or an image of unexpected dimensions.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>is_discontinued</b> - boolean, indicates if the attribute is discontinued.
|
<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
|
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,
|
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
|
it may still be in use at servers which have not been updated yet to the
|
||||||
current OKAPI version.</p>
|
current OKAPI version.</p>
|
||||||
|
|
||||||
<p><b>Important:</b> This flag can change in time. Discontinued attributes can
|
<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
|
"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>
|
encounter them in OKAPI responses, so this field is purely informative.</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -18,56 +18,56 @@ use okapi\services\attrs\AttrHelper;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# Read the parameters.
|
# Read the parameters.
|
||||||
|
|
||||||
$langpref = $request->get_parameter('langpref');
|
$langpref = $request->get_parameter('langpref');
|
||||||
if (!$langpref) $langpref = "en";
|
if (!$langpref) $langpref = "en";
|
||||||
|
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields) $fields = "name";
|
if (!$fields) $fields = "name";
|
||||||
|
|
||||||
$only_locally_used = $request->get_parameter('only_locally_used');
|
$only_locally_used = $request->get_parameter('only_locally_used');
|
||||||
if (!$only_locally_used) $only_locally_used = "false";
|
if (!$only_locally_used) $only_locally_used = "false";
|
||||||
$only_locally_used = ($only_locally_used == "true");
|
$only_locally_used = ($only_locally_used == "true");
|
||||||
|
|
||||||
# Get the list of attributes and filter the A-codes based on the
|
# Get the list of attributes and filter the A-codes based on the
|
||||||
# parameters.
|
# parameters.
|
||||||
|
|
||||||
require_once 'attr_helper.inc.php';
|
require_once 'attr_helper.inc.php';
|
||||||
$attrdict = AttrHelper::get_attrdict();
|
$attrdict = AttrHelper::get_attrdict();
|
||||||
$acodes = array();
|
$acodes = array();
|
||||||
foreach ($attrdict as $acode => &$attr_ref)
|
foreach ($attrdict as $acode => &$attr_ref)
|
||||||
{
|
{
|
||||||
if ($only_locally_used && ($attr_ref['internal_id'] === null)) {
|
if ($only_locally_used && ($attr_ref['internal_id'] === null)) {
|
||||||
/* Skip. */
|
/* Skip. */
|
||||||
continue;
|
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) {
|
if (count($acodes) > 0) {
|
||||||
$params = array(
|
$params = array(
|
||||||
'acodes' => implode("|", $acodes),
|
'acodes' => implode("|", $acodes),
|
||||||
'langpref' => $langpref,
|
'langpref' => $langpref,
|
||||||
'fields' => $fields,
|
'fields' => $fields,
|
||||||
);
|
);
|
||||||
$results = OkapiServiceRunner::call('services/attrs/attributes',
|
$results = OkapiServiceRunner::call('services/attrs/attributes',
|
||||||
new OkapiInternalRequest($request->consumer, $request->token, $params));
|
new OkapiInternalRequest($request->consumer, $request->token, $params));
|
||||||
} else {
|
} else {
|
||||||
$results = new ArrayObject();
|
$results = new ArrayObject();
|
||||||
}
|
}
|
||||||
return Okapi::formatted_response($request, $results);
|
return Okapi::formatted_response($request, $results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get the list of all OKAPI attributes (A-codes)</brief>
|
<brief>Get the list of all OKAPI attributes (A-codes)</brief>
|
||||||
<issue-id>270</issue-id>
|
<issue-id>270</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method returns <b>all</b> currently defined OKAPI geocache-attributes.
|
<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>
|
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
|
<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
|
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
|
updated servers for pre-caching attribute data</b> (currently, Opencaching.PL
|
||||||
is the most frequently updated installation). Also, you should never assume
|
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>
|
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
|
<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>
|
will its meaning change (names and descriptions can be slightly altered though).</p>
|
||||||
</desc>
|
</desc>
|
||||||
<opt name='langpref' default='en'>
|
<opt name='langpref' default='en'>
|
||||||
Works the same as in the <b>attribute</b> method.
|
Works the same as in the <b>attribute</b> method.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='fields' default='name'>
|
<opt name='fields' default='name'>
|
||||||
Works the same as in the <b>attribute</b> method.
|
Works the same as in the <b>attribute</b> method.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='only_locally_used' default='false'>
|
<opt name='only_locally_used' default='false'>
|
||||||
<p>By default, all known attributes are returned - including those which
|
<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
|
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
|
(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
|
interested only in the attributes *currently used* within *this* Opencaching
|
||||||
installation, then you may set this parameter to <b>true</b>.</p>
|
installation, then you may set this parameter to <b>true</b>.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
A dictionary. All A-codes will be mapped to dictionary keys, and
|
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.
|
each value will be an object, as described in the <b>attribute</b> method.
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -18,120 +18,120 @@ use okapi\Db;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static $valid_field_names = array(
|
private static $valid_field_names = array(
|
||||||
'acode', 'name', 'names', 'description', 'descriptions', 'gc_equivs',
|
'acode', 'name', 'names', 'description', 'descriptions', 'gc_equivs',
|
||||||
'is_locally_used', 'is_deprecated', 'local_icon_url', 'is_discontinued'
|
'is_locally_used', 'is_deprecated', 'local_icon_url', 'is_discontinued'
|
||||||
);
|
);
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# Read the parameters.
|
# Read the parameters.
|
||||||
|
|
||||||
$acodes = $request->get_parameter('acodes');
|
$acodes = $request->get_parameter('acodes');
|
||||||
if (!$acodes) throw new ParamMissing('acodes');
|
if (!$acodes) throw new ParamMissing('acodes');
|
||||||
$acodes = explode("|", $acodes);
|
$acodes = explode("|", $acodes);
|
||||||
|
|
||||||
$langpref = $request->get_parameter('langpref');
|
$langpref = $request->get_parameter('langpref');
|
||||||
if (!$langpref) $langpref = "en";
|
if (!$langpref) $langpref = "en";
|
||||||
$langpref = explode("|", $langpref);
|
$langpref = explode("|", $langpref);
|
||||||
|
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields) $fields = "name";
|
if (!$fields) $fields = "name";
|
||||||
$fields = explode("|", $fields);
|
$fields = explode("|", $fields);
|
||||||
foreach ($fields as $field)
|
foreach ($fields as $field)
|
||||||
{
|
{
|
||||||
if (!in_array($field, self::$valid_field_names))
|
if (!in_array($field, self::$valid_field_names))
|
||||||
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$forward_compatible = $request->get_parameter('forward_compatible');
|
$forward_compatible = $request->get_parameter('forward_compatible');
|
||||||
if (!$forward_compatible) $forward_compatible = "true";
|
if (!$forward_compatible) $forward_compatible = "true";
|
||||||
if (!in_array($forward_compatible, array("true", "false")))
|
if (!in_array($forward_compatible, array("true", "false")))
|
||||||
throw new InvalidParam('forward_compatible');
|
throw new InvalidParam('forward_compatible');
|
||||||
$forward_compatible = ($forward_compatible == "true");
|
$forward_compatible = ($forward_compatible == "true");
|
||||||
|
|
||||||
# Load the attributes (all of them).
|
# Load the attributes (all of them).
|
||||||
|
|
||||||
require_once 'attr_helper.inc.php';
|
require_once 'attr_helper.inc.php';
|
||||||
$attrdict = AttrHelper::get_attrdict();
|
$attrdict = AttrHelper::get_attrdict();
|
||||||
|
|
||||||
# For each A-code, check if it exists, filter its fields and add it
|
# For each A-code, check if it exists, filter its fields and add it
|
||||||
# to the results.
|
# to the results.
|
||||||
|
|
||||||
$results = array();
|
$results = array();
|
||||||
foreach ($acodes as $acode)
|
foreach ($acodes as $acode)
|
||||||
{
|
{
|
||||||
/* Please note, that the $attr variable from the $attrdict dictionary
|
/* Please note, that the $attr variable from the $attrdict dictionary
|
||||||
* below is NOT fully compatible with the interface of the "attribute"
|
* below is NOT fully compatible with the interface of the "attribute"
|
||||||
* method. Some of $attr's fields are private and should not be exposed,
|
* method. Some of $attr's fields are private and should not be exposed,
|
||||||
* other fields don't exist and have to be added dynamically! */
|
* other fields don't exist and have to be added dynamically! */
|
||||||
|
|
||||||
if (isset($attrdict[$acode])) {
|
if (isset($attrdict[$acode])) {
|
||||||
$attr = $attrdict[$acode];
|
$attr = $attrdict[$acode];
|
||||||
} elseif ($forward_compatible) {
|
} elseif ($forward_compatible) {
|
||||||
$attr = AttrHelper::get_unknown_placeholder($acode);
|
$attr = AttrHelper::get_unknown_placeholder($acode);
|
||||||
} else {
|
} else {
|
||||||
$results[$acode] = null;
|
$results[$acode] = null;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fill langpref-specific fields.
|
# Fill langpref-specific fields.
|
||||||
|
|
||||||
$attr['name'] = Okapi::pick_best_language($attr['names'], $langpref);
|
$attr['name'] = Okapi::pick_best_language($attr['names'], $langpref);
|
||||||
$attr['description'] = Okapi::pick_best_language($attr['descriptions'], $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_locally_used'] = ($attr['internal_id'] !== null);
|
||||||
$attr['is_deprecated'] = $attr['is_discontinued']; // deprecated and undocumetned field, see issue 70
|
$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
|
# 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
|
# in the $attrdict because currently we have no way of knowing then they
|
||||||
# change.)
|
# change.)
|
||||||
|
|
||||||
if (in_array('local_icon_url', $fields))
|
if (in_array('local_icon_url', $fields))
|
||||||
{
|
{
|
||||||
$tmp = Db::select_all("
|
$tmp = Db::select_all("
|
||||||
select id, icon_large
|
select id, icon_large
|
||||||
from cache_attrib
|
from cache_attrib
|
||||||
");
|
");
|
||||||
$map = array();
|
$map = array();
|
||||||
foreach ($tmp as &$row_ref) {
|
foreach ($tmp as &$row_ref) {
|
||||||
$map[$row_ref['id']] = &$row_ref;
|
$map[$row_ref['id']] = &$row_ref;
|
||||||
}
|
}
|
||||||
$prefix = Settings::get('SITE_URL');
|
$prefix = Settings::get('SITE_URL');
|
||||||
foreach ($results as &$attr_ref) {
|
foreach ($results as &$attr_ref) {
|
||||||
$internal_id = $attr_ref['internal_id'];
|
$internal_id = $attr_ref['internal_id'];
|
||||||
if (isset($map[$internal_id])) {
|
if (isset($map[$internal_id])) {
|
||||||
$row = $map[$internal_id];
|
$row = $map[$internal_id];
|
||||||
$attr_ref['local_icon_url'] = $prefix.$row['icon_large'];
|
$attr_ref['local_icon_url'] = $prefix.$row['icon_large'];
|
||||||
} else {
|
} else {
|
||||||
$attr_ref['local_icon_url'] = null;
|
$attr_ref['local_icon_url'] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Filter the fields.
|
# Filter the fields.
|
||||||
|
|
||||||
foreach ($results as &$attr_ref) {
|
foreach ($results as &$attr_ref) {
|
||||||
$clean_row = array();
|
$clean_row = array();
|
||||||
foreach ($fields as $field)
|
foreach ($fields as $field)
|
||||||
$clean_row[$field] = $attr_ref[$field];
|
$clean_row[$field] = $attr_ref[$field];
|
||||||
$attr_ref = $clean_row;
|
$attr_ref = $clean_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Okapi::formatted_response($request, $results);
|
return Okapi::formatted_response($request, $results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve data on multiple attributes at once</brief>
|
<brief>Retrieve data on multiple attributes at once</brief>
|
||||||
<issue-id>269</issue-id>
|
<issue-id>269</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method works like the <b>attribute</b> method, but
|
<p>This method works like the <b>attribute</b> method, but
|
||||||
with multiple A-codes instead of only one. Read the docs for
|
with multiple A-codes instead of only one. Read the docs for
|
||||||
the <b>attribute</b> method first!</p>
|
the <b>attribute</b> method first!</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='acodes'>
|
<req name='acodes'>
|
||||||
Pipe-separated list of A-codes you're interested in.
|
Pipe-separated list of A-codes you're interested in.
|
||||||
</req>
|
</req>
|
||||||
<opt name='langpref' default='en'>
|
<opt name='langpref' default='en'>
|
||||||
Works the same as in the <b>attribute</b> method.
|
Works the same as in the <b>attribute</b> method.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='fields' default='name'>
|
<opt name='fields' default='name'>
|
||||||
Works the same as in the <b>attribute</b> method.
|
Works the same as in the <b>attribute</b> method.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='forward_compatible' default='true'>
|
<opt name='forward_compatible' default='true'>
|
||||||
This has a similar meaning as in the <b>attribute</b> method, but works
|
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
|
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
|
for unknown keys (A-codes). You will still receive an HTTP 200 response
|
||||||
though!
|
though!
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary. A-codes you provide will be mapped to dictionary keys,
|
<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>
|
and each value will be an object, as described in the <b>attribute</b>
|
||||||
method.</p>
|
method.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -20,198 +20,202 @@ use \Exception;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
private static $shutdown_function_registered = false;
|
private static $shutdown_function_registered = false;
|
||||||
private static $files_to_unlink = array();
|
private static $files_to_unlink = array();
|
||||||
|
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$cache_codes = $request->get_parameter('cache_codes');
|
$cache_codes = $request->get_parameter('cache_codes');
|
||||||
if ($cache_codes === null) throw new ParamMissing('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.
|
# 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!
|
# All of the queries below have to be ready for $cache_codes to be empty!
|
||||||
|
|
||||||
$langpref = $request->get_parameter('langpref');
|
$langpref = $request->get_parameter('langpref');
|
||||||
if (!$langpref) $langpref = "en";
|
if (!$langpref) $langpref = "en";
|
||||||
$images = $request->get_parameter('images');
|
$images = $request->get_parameter('images');
|
||||||
if (!$images) $images = "all";
|
if (!$images) $images = "all";
|
||||||
if (!in_array($images, array("none", "all", "spoilers", "nonspoilers")))
|
if (!in_array($images, array("none", "all", "spoilers", "nonspoilers")))
|
||||||
throw new InvalidParam('images');
|
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";
|
$tempfilename = Okapi::get_var_dir()."/garmin".time().rand(100000,999999).".zip";
|
||||||
$zip = new ZipArchive();
|
$zip = new ZipArchive();
|
||||||
if ($zip->open($tempfilename, ZIPARCHIVE::CREATE) !== true)
|
if ($zip->open($tempfilename, ZIPARCHIVE::CREATE) !== true)
|
||||||
throw new Exception("ZipArchive class could not create temp file $tempfilename. Check permissions!");
|
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");
|
||||||
$zip->addEmptyDir("Garmin/GPX");
|
$zip->addEmptyDir("Garmin/GPX");
|
||||||
$zip->addEmptyDir("Garmin/GeocachePhotos");
|
$zip->addEmptyDir("Garmin/GeocachePhotos");
|
||||||
|
|
||||||
# Include a GPX file compatible with Garmin devices. It should include all
|
# Include a GPX file compatible with Garmin devices. It should include all
|
||||||
# Geocaching.com (groundspeak:) and Opencaching.com (ox:) extensions. It will
|
# Geocaching.com (groundspeak:) and Opencaching.com (ox:) extensions. It will
|
||||||
# also include image references (actual images will be added as separate files later)
|
# 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).
|
# and personal data (if the method was invoked using Level 3 Authentication).
|
||||||
|
|
||||||
$zip->addFromString("Garmin/GPX/opencaching".time().rand(100000,999999).".gpx",
|
$zip->addFromString("Garmin/GPX/opencaching".time().rand(100000,999999).".gpx",
|
||||||
OkapiServiceRunner::call('services/caches/formatters/gpx', new OkapiInternalRequest(
|
OkapiServiceRunner::call('services/caches/formatters/gpx', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array(
|
$request->consumer, $request->token, array(
|
||||||
'cache_codes' => $cache_codes,
|
'cache_codes' => $cache_codes,
|
||||||
'langpref' => $langpref,
|
'langpref' => $langpref,
|
||||||
'ns_ground' => 'true',
|
'ns_ground' => 'true',
|
||||||
'ns_ox' => 'true',
|
'ns_ox' => 'true',
|
||||||
'images' => 'ox:all',
|
'images' => 'ox:all',
|
||||||
'attrs' => 'ox:tags',
|
'attrs' => 'ox:tags',
|
||||||
'trackables' => 'desc:count',
|
'trackables' => 'desc:count',
|
||||||
'alt_wpts' => 'true',
|
'alt_wpts' => 'true',
|
||||||
'recommendations' => 'desc:count',
|
'recommendations' => 'desc:count',
|
||||||
'latest_logs' => 'true',
|
'latest_logs' => 'true',
|
||||||
'lpc' => 'all',
|
'lpc' => 'all',
|
||||||
'my_notes' => ($request->token != null) ? "desc:text" : "none"
|
'my_notes' => ($request->token != null) ? "desc:text" : "none",
|
||||||
)))->get_body());
|
'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(
|
$caches = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('cache_codes' => $cache_codes,
|
$request->consumer, $request->token, array('cache_codes' => $cache_codes,
|
||||||
'langpref' => $langpref, 'fields' => "images")));
|
'langpref' => $langpref, 'fields' => "images")));
|
||||||
if (count($caches) > 50)
|
if (count($caches) > 50)
|
||||||
throw new InvalidParam('cache_codes', "The maximum number of caches allowed to be downloaded with this method is 50.");
|
throw new InvalidParam('cache_codes', "The maximum number of caches allowed to be downloaded with this method is 50.");
|
||||||
if ($images != 'none')
|
if ($images != 'none')
|
||||||
{
|
{
|
||||||
$supported_extensions = array('jpg', 'jpeg', 'gif', 'png', 'bmp');
|
$supported_extensions = array('jpg', 'jpeg', 'gif', 'png', 'bmp');
|
||||||
foreach ($caches as $cache_code => $dict)
|
foreach ($caches as $cache_code => $dict)
|
||||||
{
|
{
|
||||||
$imgs = $dict['images'];
|
$imgs = $dict['images'];
|
||||||
if (count($imgs) == 0)
|
if (count($imgs) == 0)
|
||||||
continue;
|
continue;
|
||||||
$dir = "Garmin/GeocachePhotos/".$cache_code[strlen($cache_code) - 1];
|
$dir = "Garmin/GeocachePhotos/".$cache_code[strlen($cache_code) - 1];
|
||||||
$zip->addEmptyDir($dir); # fails silently if it already exists
|
$zip->addEmptyDir($dir); # fails silently if it already exists
|
||||||
$dir .= "/".$cache_code[strlen($cache_code) - 2];
|
$dir .= "/".$cache_code[strlen($cache_code) - 2];
|
||||||
$zip->addEmptyDir($dir);
|
$zip->addEmptyDir($dir);
|
||||||
$dir .= "/".$cache_code;
|
$dir .= "/".$cache_code;
|
||||||
$zip->addEmptyDir($dir);
|
$zip->addEmptyDir($dir);
|
||||||
foreach ($imgs as $no => $img)
|
foreach ($imgs as $no => $img)
|
||||||
{
|
{
|
||||||
if ($images == 'spoilers' && (!$img['is_spoiler']))
|
if ($images == 'spoilers' && (!$img['is_spoiler']))
|
||||||
continue;
|
continue;
|
||||||
if ($images == 'nonspoilers' && $img['is_spoiler'])
|
if ($images == 'nonspoilers' && $img['is_spoiler'])
|
||||||
continue;
|
continue;
|
||||||
$tmp = false;
|
$tmp = false;
|
||||||
foreach ($supported_extensions as $ext)
|
foreach ($supported_extensions as $ext)
|
||||||
{
|
{
|
||||||
if (strtolower(substr($img['url'], strlen($img['url']) - strlen($ext) - 1)) != ".".$ext)
|
if (strtolower(substr($img['url'], strlen($img['url']) - strlen($ext) - 1)) != ".".$ext)
|
||||||
{
|
{
|
||||||
$tmp = true;
|
$tmp = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$tmp)
|
if (!$tmp)
|
||||||
continue; # unsupported file extension
|
continue; # unsupported file extension
|
||||||
|
|
||||||
if ($img['is_spoiler']) {
|
if ($img['is_spoiler']) {
|
||||||
$zip->addEmptyDir($dir."/Spoilers");
|
$zip->addEmptyDir($dir."/Spoilers");
|
||||||
$zippath = $dir."/Spoilers/".$img['unique_caption'].".jpg";
|
$zippath = $dir."/Spoilers/".$img['unique_caption'].".jpg";
|
||||||
} else {
|
} else {
|
||||||
$zippath = $dir."/".$img['unique_caption'].".jpg";
|
$zippath = $dir."/".$img['unique_caption'].".jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
# The safest way would be to use the URL, but that would be painfully slow!
|
# 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).
|
# That's why we're trying to access files directly (and fail silently on error).
|
||||||
# This was tested on OCPL server only.
|
# This was tested on OCPL server only.
|
||||||
|
|
||||||
# Note: Oliver Dietz (oc.de) replied that images with 'local' set to 0 could not
|
# 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.
|
# be accessed locally. But all the files have 'local' set to 1 anyway.
|
||||||
|
|
||||||
$syspath = Settings::get('IMAGES_DIR')."/".$img['uuid'].".jpg";
|
$syspath = Settings::get('IMAGES_DIR')."/".$img['uuid'].".jpg";
|
||||||
if (file_exists($syspath))
|
if (file_exists($syspath))
|
||||||
{
|
{
|
||||||
$file = file_get_contents($syspath);
|
$file = file_get_contents($syspath);
|
||||||
if ($file)
|
if ($file)
|
||||||
$zip->addFromString($zippath, $file);
|
$zip->addFromString($zippath, $file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
# If file exists, but does not end with ".jpg", we will create
|
# If file exists, but does not end with ".jpg", we will create
|
||||||
# JPEG version of it and store it in the cache.
|
# JPEG version of it and store it in the cache.
|
||||||
|
|
||||||
$cache_key = "jpg#".$img['uuid'];
|
$cache_key = "jpg#".$img['uuid'];
|
||||||
$jpeg_contents = Cache::get($cache_key);
|
$jpeg_contents = Cache::get($cache_key);
|
||||||
if ($jpeg_contents === null)
|
if ($jpeg_contents === null)
|
||||||
{
|
{
|
||||||
foreach ($supported_extensions as $ext)
|
foreach ($supported_extensions as $ext)
|
||||||
{
|
{
|
||||||
$syspath_other = Settings::get('IMAGES_DIR')."/".$img['uuid'].".".$ext;
|
$syspath_other = Settings::get('IMAGES_DIR')."/".$img['uuid'].".".$ext;
|
||||||
if (file_exists($syspath_other))
|
if (file_exists($syspath_other))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$image = imagecreatefromstring(file_get_contents($syspath_other));
|
$image = imagecreatefromstring(file_get_contents($syspath_other));
|
||||||
ob_start();
|
ob_start();
|
||||||
imagejpeg($image);
|
imagejpeg($image);
|
||||||
$jpeg_contents = ob_get_clean();
|
$jpeg_contents = ob_get_clean();
|
||||||
imagedestroy($image);
|
imagedestroy($image);
|
||||||
}
|
}
|
||||||
catch (Exception $e)
|
catch (Exception $e)
|
||||||
{
|
{
|
||||||
# GD couldn't parse the file. We will skip it, and cache
|
# GD couldn't parse the file. We will skip it, and cache
|
||||||
# the "false" value as the contents. This way, we won't
|
# the "false" value as the contents. This way, we won't
|
||||||
# attempt to parse it during the next 24 hours.
|
# attempt to parse it during the next 24 hours.
|
||||||
|
|
||||||
$jpeg_contents = false;
|
$jpeg_contents = false;
|
||||||
}
|
}
|
||||||
Cache::set($cache_key, $jpeg_contents, 86400);
|
Cache::set($cache_key, $jpeg_contents, 86400);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($jpeg_contents) # This can be "null" *or* "false"!
|
if ($jpeg_contents) # This can be "null" *or* "false"!
|
||||||
$zip->addFromString($zippath, $jpeg_contents);
|
$zip->addFromString($zippath, $jpeg_contents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$zip->close();
|
$zip->close();
|
||||||
|
|
||||||
# The result could be big. Bigger than our memory limit. We will
|
# The result could be big. Bigger than our memory limit. We will
|
||||||
# return an open file stream instead of a string. We also should
|
# return an open file stream instead of a string. We also should
|
||||||
# set a higher time limit, because downloading this response may
|
# set a higher time limit, because downloading this response may
|
||||||
# take some time over slow network connections (and I'm not sure
|
# take some time over slow network connections (and I'm not sure
|
||||||
# what is the PHP's default way of handling such scenario).
|
# what is the PHP's default way of handling such scenario).
|
||||||
|
|
||||||
set_time_limit(600);
|
set_time_limit(600);
|
||||||
$response = new OkapiHttpResponse();
|
$response = new OkapiHttpResponse();
|
||||||
$response->content_type = "application/zip";
|
$response->content_type = "application/zip";
|
||||||
$response->content_disposition = 'attachment; filename="results.zip"';
|
$response->content_disposition = 'attachment; filename="results.zip"';
|
||||||
$response->stream_length = filesize($tempfilename);
|
$response->stream_length = filesize($tempfilename);
|
||||||
$response->body = fopen($tempfilename, "rb");
|
$response->body = fopen($tempfilename, "rb");
|
||||||
$response->allow_gzip = false;
|
$response->allow_gzip = false;
|
||||||
self::add_file_to_unlink($tempfilename);
|
self::add_file_to_unlink($tempfilename);
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function add_file_to_unlink($filename)
|
private static function add_file_to_unlink($filename)
|
||||||
{
|
{
|
||||||
if (!self::$shutdown_function_registered)
|
if (!self::$shutdown_function_registered)
|
||||||
register_shutdown_function(array("okapi\\services\\caches\\formatters\\garmin\\WebService", "unlink_temporary_files"));
|
register_shutdown_function(array("okapi\\services\\caches\\formatters\\garmin\\WebService", "unlink_temporary_files"));
|
||||||
self::$files_to_unlink[] = $filename;
|
self::$files_to_unlink[] = $filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function unlink_temporary_files()
|
public static function unlink_temporary_files()
|
||||||
{
|
{
|
||||||
foreach (self::$files_to_unlink as $filename)
|
foreach (self::$files_to_unlink as $filename)
|
||||||
@unlink($filename);
|
@unlink($filename);
|
||||||
self::$files_to_unlink = array();
|
self::$files_to_unlink = array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,55 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve ZIP file for Garmin devices</brief>
|
<brief>Retrieve ZIP file for Garmin devices</brief>
|
||||||
<issue-id>99</issue-id>
|
<issue-id>99</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Produce a ZIP file with content compatible with Geocaching-enabled Garmin
|
<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
|
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
|
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
|
(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>
|
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
|
<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
|
with the chosen geocaches. Options for the GPX file are fixed, use the
|
||||||
services/caches/formatters/gpx method if
|
services/caches/formatters/gpx method if
|
||||||
you want a custom-tailored GPX file.</p>
|
you want a custom-tailored GPX file.</p>
|
||||||
<p><b>Important note:</b> The contents of the returned ZIP archive may change in the
|
<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
|
future. You should not parse the contents, nor assume that they have any specific
|
||||||
structure.</p>
|
structure.</p>
|
||||||
<p><b>Important note:</b> We might be increasing required authentication level for
|
<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
|
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>,
|
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>
|
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
|
<p><b>Note:</b> All non-JPEG images will be skipped. Currently OKAPI does not convert
|
||||||
other types of images to JPEG.</p>
|
other types of images to JPEG.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='cache_codes'>
|
<req name='cache_codes'>
|
||||||
<p>Pipe-separated list of cache codes which you are interested in.
|
<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
|
No more than 50 codes are allowed. (This limit is smaller than usual, because
|
||||||
we're afraid about the sizes of ZIP files produced.)
|
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>
|
This CAN be an empty string (it will still result in a valid ZIP file).</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='langpref' default='en'>
|
<opt name='langpref' default='en'>
|
||||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
<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>
|
order of preference in which language will be chosen for GPX entities.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='images' default='all'>
|
<opt name='images' default='all'>
|
||||||
<p>One of the following values:</p>
|
<p>One of the following values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>none</b> - no images will be included in the result,</li>
|
<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>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>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>
|
<li><b>nonspoilers</b> - only non-spoiler images will be included in the result.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</opt>
|
</opt>
|
||||||
<returns>
|
<opt name="location_source" default='default-coords'>
|
||||||
<p>ZIP file. You should extract it's contents directly into the root
|
Same as in the <a href="%OKAPI:methodargref:services/caches/formatters/gpx#location_source%">
|
||||||
directory of your Garmin's internal memory storage.</p>
|
services/caches/formatters/gpx</a> method.
|
||||||
</returns>
|
</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>
|
</xml>
|
||||||
@@ -19,297 +19,383 @@ use okapi\services\attrs\AttrHelper;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Maps OKAPI cache type codes to Geocaching.com GPX cache types. */
|
/** Maps OKAPI cache type codes to Geocaching.com GPX cache types. */
|
||||||
public static $cache_GPX_types = array(
|
public static $cache_GPX_types = array(
|
||||||
'Traditional' => 'Traditional Cache',
|
'Traditional' => 'Traditional Cache',
|
||||||
'Multi' => 'Multi-Cache',
|
'Multi' => 'Multi-Cache',
|
||||||
'Quiz' => 'Unknown Cache',
|
'Quiz' => 'Unknown Cache',
|
||||||
'Event' => 'Event Cache',
|
'Event' => 'Event Cache',
|
||||||
'Virtual' => 'Virtual Cache',
|
'Virtual' => 'Virtual Cache',
|
||||||
'Webcam' => 'Webcam Cache',
|
'Webcam' => 'Webcam Cache',
|
||||||
'Moving' => 'Unknown Cache',
|
'Moving' => 'Unknown Cache',
|
||||||
'Math/Physics' => 'Unknown Cache',
|
'Math/Physics' => 'Unknown Cache',
|
||||||
'Drive-In' => 'Traditional Cache',
|
'Drive-In' => 'Traditional Cache',
|
||||||
'Own' => 'Unknown Cache',
|
'Podcast' => 'Unknown Cache',
|
||||||
'Other' => 'Unknown Cache'
|
'Own' => 'Unknown Cache',
|
||||||
);
|
'Other' => 'Unknown Cache'
|
||||||
|
);
|
||||||
|
|
||||||
/** Maps OKAPI's 'size2' values to geocaching.com size codes. */
|
/** Maps OKAPI's 'size2' values to geocaching.com size codes. */
|
||||||
public static $cache_GPX_sizes = array(
|
public static $cache_GPX_sizes = array(
|
||||||
'none' => 'Virtual',
|
'none' => 'Virtual',
|
||||||
'nano' => 'Micro',
|
'nano' => 'Micro',
|
||||||
'micro' => 'Micro',
|
'micro' => 'Micro',
|
||||||
'small' => 'Small',
|
'small' => 'Small',
|
||||||
'regular' => 'Regular',
|
'regular' => 'Regular',
|
||||||
'large' => 'Large',
|
'large' => 'Large',
|
||||||
'xlarge' => 'Large',
|
'xlarge' => 'Large',
|
||||||
'other' => 'Other',
|
'other' => 'Other',
|
||||||
);
|
);
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$vars = array();
|
$vars = array();
|
||||||
|
|
||||||
# Validating arguments. We will also assign some of them to the
|
# Validating arguments. We will also assign some of them to the
|
||||||
# $vars variable which we will use later in the GPS template.
|
# $vars variable which we will use later in the GPS template.
|
||||||
|
|
||||||
$cache_codes = $request->get_parameter('cache_codes');
|
$cache_codes = $request->get_parameter('cache_codes');
|
||||||
if ($cache_codes === null) throw new ParamMissing('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.
|
# 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!
|
# All of the queries below have to be ready for $cache_codes to be empty!
|
||||||
|
|
||||||
$langpref = $request->get_parameter('langpref');
|
$langpref = $request->get_parameter('langpref');
|
||||||
if (!$langpref) $langpref = "en";
|
if (!$langpref) $langpref = "en";
|
||||||
foreach (array('ns_ground', 'ns_gsak', 'ns_ox', 'latest_logs', 'alt_wpts', 'mark_found') as $param)
|
foreach (array('ns_ground', 'ns_gsak', 'ns_ox', 'latest_logs', 'alt_wpts', 'mark_found') as $param)
|
||||||
{
|
{
|
||||||
$val = $request->get_parameter($param);
|
$val = $request->get_parameter($param);
|
||||||
if (!$val) $val = "false";
|
if (!$val) $val = "false";
|
||||||
elseif (!in_array($val, array("true", "false")))
|
elseif (!in_array($val, array("true", "false")))
|
||||||
throw new InvalidParam($param);
|
throw new InvalidParam($param);
|
||||||
$vars[$param] = ($val == "true");
|
$vars[$param] = ($val == "true");
|
||||||
}
|
}
|
||||||
if ($vars['latest_logs'] && (!$vars['ns_ground']))
|
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.");
|
throw new BadRequest("In order for 'latest_logs' to work you have to also include 'ns_ground' extensions.");
|
||||||
|
|
||||||
$tmp = $request->get_parameter('my_notes');
|
$tmp = $request->get_parameter('my_notes');
|
||||||
$vars['my_notes'] = array();
|
$vars['my_notes'] = array();
|
||||||
if ($tmp && $tmp != 'none') {
|
if ($tmp && $tmp != 'none') {
|
||||||
$tmp = explode('|', $tmp);
|
$tmp = explode('|', $tmp);
|
||||||
foreach ($tmp as $elem) {
|
foreach ($tmp as $elem) {
|
||||||
if ($elem == 'none') {
|
if ($elem == 'none') {
|
||||||
/* pass */
|
/* pass */
|
||||||
} elseif (in_array($elem, array('desc:text', 'gc:personal_note'))) {
|
} elseif (in_array($elem, array('desc:text', 'gc:personal_note'))) {
|
||||||
if (in_array('none', $tmp)) {
|
if (in_array('none', $tmp)) {
|
||||||
throw new InvalidParam(
|
throw new InvalidParam(
|
||||||
'my_notes', "You cannot mix 'none' and '$elem'"
|
'my_notes', "You cannot mix 'none' and '$elem'"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ($request->token == null) {
|
if ($request->token == null) {
|
||||||
throw new BadRequest(
|
throw new BadRequest(
|
||||||
"Level 3 Authentication is required to access my_notes data."
|
"Level 3 Authentication is required to access my_notes data."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$vars['my_notes'][] = $elem;
|
$vars['my_notes'][] = $elem;
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidParam('my_notes', "Invalid list entry: '$elem'");
|
throw new InvalidParam('my_notes', "Invalid list entry: '$elem'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$images = $request->get_parameter('images');
|
$images = $request->get_parameter('images');
|
||||||
if (!$images) $images = 'descrefs:nonspoilers';
|
if (!$images) $images = 'descrefs:nonspoilers';
|
||||||
if (!in_array($images, array('none', 'descrefs:thumblinks', 'descrefs:nonspoilers', 'descrefs:all', 'ox:all')))
|
if (!in_array($images, array('none', 'descrefs:thumblinks', 'descrefs:nonspoilers', 'descrefs:all', 'ox:all')))
|
||||||
throw new InvalidParam('images', "'$images'");
|
throw new InvalidParam('images', "'$images'");
|
||||||
$vars['images'] = $images;
|
$vars['images'] = $images;
|
||||||
|
|
||||||
$tmp = $request->get_parameter('attrs');
|
$tmp = $request->get_parameter('attrs');
|
||||||
if (!$tmp) $tmp = 'desc:text';
|
if (!$tmp) $tmp = 'desc:text';
|
||||||
$tmp = explode("|", $tmp);
|
$tmp = explode("|", $tmp);
|
||||||
$vars['attrs'] = array();
|
$vars['attrs'] = array();
|
||||||
foreach ($tmp as $elem)
|
foreach ($tmp as $elem)
|
||||||
{
|
{
|
||||||
if ($elem == 'none') {
|
if ($elem == 'none') {
|
||||||
/* pass */
|
/* pass */
|
||||||
} elseif (in_array($elem, array('desc:text', 'ox:tags', 'gc:attrs', 'gc_ocde:attrs'))) {
|
} 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')
|
if ($elem == 'gc_ocde:attrs' && Settings::get('OC_BRANCH') != 'oc.de')
|
||||||
$vars['attrs'][] = 'gc:attrs';
|
$vars['attrs'][] = 'gc:attrs';
|
||||||
else
|
else
|
||||||
$vars['attrs'][] = $elem;
|
$vars['attrs'][] = $elem;
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidParam('attrs', "Invalid list entry: '$elem'");
|
throw new InvalidParam('attrs', "Invalid list entry: '$elem'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$protection_areas = $request->get_parameter('protection_areas');
|
$protection_areas = $request->get_parameter('protection_areas');
|
||||||
if (!$protection_areas || $protection_areas == 'desc:auto')
|
if (!$protection_areas || $protection_areas == 'desc:auto')
|
||||||
{
|
{
|
||||||
if (Settings::get('OC_BRANCH') == 'oc.de') $protection_areas = 'desc:text';
|
if (Settings::get('OC_BRANCH') == 'oc.de') $protection_areas = 'desc:text';
|
||||||
else $protection_areas = 'none';
|
else $protection_areas = 'none';
|
||||||
}
|
}
|
||||||
if (!in_array($protection_areas, array('none', 'desc:text')))
|
if (!in_array($protection_areas, array('none', 'desc:text')))
|
||||||
throw new InvalidParam('protection_areas',"'$protection_areas'");
|
throw new InvalidParam('protection_areas',"'$protection_areas'");
|
||||||
$vars['protection_areas'] = $protection_areas;
|
$vars['protection_areas'] = $protection_areas;
|
||||||
|
|
||||||
$tmp = $request->get_parameter('trackables');
|
$tmp = $request->get_parameter('trackables');
|
||||||
if (!$tmp) $tmp = 'none';
|
if (!$tmp) $tmp = 'none';
|
||||||
if (!in_array($tmp, array('none', 'desc:list', 'desc:count')))
|
if (!in_array($tmp, array('none', 'desc:list', 'desc:count')))
|
||||||
throw new InvalidParam('trackables', "'$tmp'");
|
throw new InvalidParam('trackables', "'$tmp'");
|
||||||
$vars['trackables'] = $tmp;
|
$vars['trackables'] = $tmp;
|
||||||
|
|
||||||
$tmp = $request->get_parameter('recommendations');
|
$tmp = $request->get_parameter('recommendations');
|
||||||
if (!$tmp) $tmp = 'none';
|
if (!$tmp) $tmp = 'none';
|
||||||
if (!in_array($tmp, array('none', 'desc:count')))
|
if (!in_array($tmp, array('none', 'desc:count')))
|
||||||
throw new InvalidParam('recommendations', "'$tmp'");
|
throw new InvalidParam('recommendations', "'$tmp'");
|
||||||
$vars['recommendations'] = $tmp;
|
$vars['recommendations'] = $tmp;
|
||||||
|
|
||||||
$lpc = $request->get_parameter('lpc');
|
$lpc = $request->get_parameter('lpc');
|
||||||
if ($lpc === null) $lpc = 10; # will be checked in services/caches/geocaches call
|
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'.
|
$location_source = $request->get_parameter('location_source');
|
||||||
'|difficulty|terrain|description|hint2|rating|owner|url|internal_id'.
|
if (!$location_source)
|
||||||
'|protection_areas';
|
{
|
||||||
if ($vars['images'] != 'none')
|
$location_source = 'default-coords';
|
||||||
$fields .= "|images";
|
}
|
||||||
if (count($vars['attrs']) > 0)
|
# Make sure location_source has prefix alt_wpt:
|
||||||
$fields .= "|attrnames|attr_acodes";
|
if ($location_source != 'default-coords' && strncmp($location_source, 'alt_wpt:', 8) != 0)
|
||||||
if ($vars['trackables'] == 'desc:list')
|
{
|
||||||
$fields .= "|trackables";
|
throw new InvalidParam('location_source', '\''.$location_source.'\'');
|
||||||
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";
|
|
||||||
|
|
||||||
$vars['caches'] = OkapiServiceRunner::call(
|
# Make sure we have sufficient authorization
|
||||||
'services/caches/geocaches', new OkapiInternalRequest(
|
if ($location_source == 'alt_wpt:user-coords' && $request->token == null)
|
||||||
$request->consumer, $request->token, array(
|
{
|
||||||
'cache_codes' => $cache_codes,
|
throw new BadRequest("Level 3 Authentication is required to access 'alt_wpt:user-coords'.");
|
||||||
'langpref' => $langpref,
|
}
|
||||||
'fields' => $fields,
|
|
||||||
'lpc' => $lpc,
|
|
||||||
'user_uuid' => $user_uuid,
|
|
||||||
'log_fields' => 'uuid|date|user|type|comment|internal_id|was_recommended'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
# Get all the other data need.
|
# Which fields of the services/caches/geocaches method do we need?
|
||||||
|
|
||||||
$vars['installation'] = OkapiServiceRunner::call(
|
$fields = 'code|name|location|date_created|url|type|status|size|size2|oxsize'.
|
||||||
'services/apisrv/installation', new OkapiInternalRequest(
|
'|difficulty|terrain|description|hint2|rating|owner|url|internal_id'.
|
||||||
new OkapiInternalConsumer(), null, array()
|
'|protection_areas|short_description';
|
||||||
)
|
if ($vars['images'] != 'none')
|
||||||
);
|
$fields .= "|images";
|
||||||
$vars['cache_GPX_types'] = self::$cache_GPX_types;
|
if (count($vars['attrs']) > 0)
|
||||||
$vars['cache_GPX_sizes'] = self::$cache_GPX_sizes;
|
$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)
|
$vars['caches'] = OkapiServiceRunner::call(
|
||||||
{
|
'services/caches/geocaches', new OkapiInternalRequest(
|
||||||
/* The user asked for some kind of attribute output. We'll fetch all
|
$request->consumer, $request->token, array(
|
||||||
* the data we MAY need. This is often far too much, but thanks to
|
'cache_codes' => $cache_codes,
|
||||||
* caching, it will work fast. */
|
'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(
|
# Get rid of invalid cache references.
|
||||||
'services/attrs/attribute_index', new OkapiInternalRequest(
|
|
||||||
$request->consumer, $request->token, array(
|
|
||||||
'only_locally_used' => 'true',
|
|
||||||
'langpref' => $langpref,
|
|
||||||
'fields' => 'name|gc_equivs'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
# prepare GS attribute data
|
$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']);
|
# Get all the other data need.
|
||||||
$vars['gc_ocde_attrs'] = in_array('gc_ocde:attrs', $vars['attrs']);
|
|
||||||
if ($vars['gc_attrs'] || $vars['gc_ocde_attrs'])
|
|
||||||
{
|
|
||||||
if ($vars['gc_ocde_attrs'])
|
|
||||||
{
|
|
||||||
# As this is an OCDE compatibility feature, we use the same Pseudo-GS
|
|
||||||
# attribute names here as OCDE. Note that this code is specific to OCDE
|
|
||||||
# database; OCPL stores attribute names in a different way and may use
|
|
||||||
# different names for equivalent attributes.
|
|
||||||
|
|
||||||
$ocde_attrnames = Db::select_group_by('id',"
|
$vars['installation'] = OkapiServiceRunner::call(
|
||||||
select id, name
|
'services/apisrv/installation', new OkapiInternalRequest(
|
||||||
from cache_attrib
|
new OkapiInternalConsumer(), null, array()
|
||||||
");
|
)
|
||||||
$attr_dict = AttrHelper::get_attrdict();
|
);
|
||||||
}
|
$vars['cache_GPX_types'] = self::$cache_GPX_types;
|
||||||
|
$vars['cache_GPX_sizes'] = self::$cache_GPX_sizes;
|
||||||
|
|
||||||
foreach ($vars['caches'] as &$cache)
|
if (count($vars['attrs']) > 0)
|
||||||
{
|
{
|
||||||
$cache['gc_attrs'] = array();
|
/* The user asked for some kind of attribute output. We'll fetch all
|
||||||
foreach ($cache['attr_acodes'] as $acode)
|
* the data we MAY need. This is often far too much, but thanks to
|
||||||
{
|
* caching, it will work fast. */
|
||||||
$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['gc_attrs'][$gc['id']] = $gc;
|
$vars['attr_index'] = OkapiServiceRunner::call(
|
||||||
$has_gc_equivs = true;
|
'services/attrs/attribute_index', new OkapiInternalRequest(
|
||||||
}
|
$request->consumer, $request->token, array(
|
||||||
if (!$has_gc_equivs && $vars['gc_ocde_attrs'])
|
'only_locally_used' => 'true',
|
||||||
{
|
'langpref' => $langpref,
|
||||||
# Generate an OCDE pseudo-GS attribute;
|
'fields' => 'name|gc_equivs'
|
||||||
# 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'];
|
# prepare GS attribute data
|
||||||
$cache['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.
|
$vars['gc_attrs'] = in_array('gc:attrs', $vars['attrs']);
|
||||||
* This might be considered an error in itself (Groundspeak's XML namespace
|
$vars['gc_ocde_attrs'] = in_array('gc_ocde:attrs', $vars['attrs']);
|
||||||
* doesn't allow that), but it very common (Garmin's OpenCaching.COM
|
if ($vars['gc_attrs'] || $vars['gc_ocde_attrs'])
|
||||||
* also does that). Therefore, for backward-compatibility reasons, OKAPI
|
{
|
||||||
* will do it the same way. See issue 174.
|
if ($vars['gc_ocde_attrs'])
|
||||||
*
|
{
|
||||||
* Currently, the caches method does not expose "owner.internal_id" and
|
# As this is an OCDE compatibility feature, we use the same Pseudo-GS
|
||||||
* "latest_logs.user.internal_id" fields, we will read them manually
|
# attribute names here as OCDE. Note that this code is specific to OCDE
|
||||||
* from the database here. */
|
# database; OCPL stores attribute names in a different way and may use
|
||||||
|
# different names for equivalent attributes.
|
||||||
|
|
||||||
$dict = array();
|
$ocde_attrnames = Db::select_group_by('id',"
|
||||||
foreach ($vars['caches'] as &$cache_ref)
|
select id, name
|
||||||
{
|
from cache_attrib
|
||||||
$dict[$cache_ref['owner']['uuid']] = true;
|
");
|
||||||
if (isset($cache_ref['latest_logs']))
|
$attr_dict = AttrHelper::get_attrdict();
|
||||||
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);
|
|
||||||
|
|
||||||
$response = new OkapiHttpResponse();
|
foreach ($vars['caches'] as &$cache_ref)
|
||||||
$response->content_type = "application/gpx; charset=utf-8";
|
{
|
||||||
$response->content_disposition = 'attachment; filename="results.gpx"';
|
$cache_ref['gc_attrs'] = array();
|
||||||
ob_start();
|
foreach ($cache_ref['attr_acodes'] as $acode)
|
||||||
Okapi::gettext_domain_init(explode("|", $langpref)); # Consumer gets properly localized GPX file.
|
{
|
||||||
include 'gpxfile.tpl.php';
|
$has_gc_equivs = false;
|
||||||
Okapi::gettext_domain_restore();
|
foreach ($vars['attr_index'][$acode]['gc_equivs'] as $gc)
|
||||||
$response->body = ob_get_clean();
|
{
|
||||||
return $response;
|
# 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>
|
<xml>
|
||||||
<brief>Retrieve geocaches in GPX format</brief>
|
<brief>Retrieve geocaches in GPX format</brief>
|
||||||
<issue-id>40</issue-id>
|
<issue-id>40</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Produces a standards-compliant Geocaching GPX file.</p>
|
<p>Produces a standards-compliant Geocaching GPX file.</p>
|
||||||
<p>Unlike the services/caches/geocaches method responses, GPX files cannot
|
<p>Unlike the services/caches/geocaches method responses, GPX files cannot
|
||||||
contain names and descriptions in separate multiple languages. This method
|
contain names and descriptions in separate multiple languages. This method
|
||||||
will attempt to choose the best language based on your preference
|
will attempt to choose the best language based on your preference
|
||||||
(see <b>langpref</b> argument).</p>
|
(see <b>langpref</b> argument).</p>
|
||||||
<p>Remember that a full-blown GPX file is much larger than a basic one.
|
<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
|
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
|
waypoints takes ~50 times less space than the same list with cache descriptions
|
||||||
and log entries included.</p>
|
and log entries included.</p>
|
||||||
<p>Note, that GPX files may contain <a href='%OKAPI:docurl:html%'>unvalidated
|
<p>Note, that GPX files may contain <a href='%OKAPI:docurl:html%'>unvalidated
|
||||||
HTML</a>.</p>
|
HTML</a>.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='cache_codes'>
|
<req name='cache_codes'>
|
||||||
<p>Pipe-separated list of cache codes which you are interested in.
|
<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
|
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
|
result in an empty, but valid, GPX file). All invalid cache codes will
|
||||||
be skipped without any notice!</p>
|
be skipped without any notice!</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='langpref' default='en'>
|
<opt name='langpref' default='en'>
|
||||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
<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>
|
order of preference in which language will be chosen for GPX entities.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='ns_ground' default='false'>
|
<opt name='ns_ground' default='false'>
|
||||||
Boolean. If <b>true</b> then response will include
|
Boolean. If <b>true</b> then response will include
|
||||||
<a href='http://www.groundspeak.com/cache/1/0/1/cache.xsd'>Groundspeak's
|
<a href='http://www.groundspeak.com/cache/1/0/1/cache.xsd'>Groundspeak's
|
||||||
GPX extension</a>. This namespace declares an extra <cache> element
|
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>.
|
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
|
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.
|
be used in every geocaching GPX file. You probably want to have it.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='ns_gsak' default='false'>
|
<opt name='ns_gsak' default='false'>
|
||||||
<p>Boolean. If <b>true</b> then response will include
|
<p>Boolean. If <b>true</b> then response will include
|
||||||
<a href='http://www.gsak.net/xmlv1/5/gsak.xsd'>GSAK GPX extension</a>.
|
<a href='http://www.gsak.net/xmlv1/5/gsak.xsd'>GSAK GPX extension</a>.
|
||||||
This namespace declares an extra <wptExtension> element,
|
This namespace declares an extra <wptExtension> element,
|
||||||
which allows including "waypoint inheritance" information (parent-child relations).
|
which allows including "waypoint inheritance" information (parent-child relations).
|
||||||
This in turn allows us to include "alternate waypoints" in the response.</p>
|
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
|
<p>We know of <b>at least</b> <a href='http://www.gsak.net/'>one tool</a> that
|
||||||
makes use of this.</p>
|
makes use of this.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='ns_ox' default='false'>
|
<opt name='ns_ox' default='false'>
|
||||||
Boolean. If <b>true</b> then response will include Garmin's
|
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
|
<a href='http://www.opencaching.com/xmlschemas/opencaching/1/0/opencaching.xsd'>OpenCaching.com
|
||||||
GPX extension</a>. This namespace declares an extra <opencaching> element
|
GPX extension</a>. This namespace declares an extra <opencaching> element
|
||||||
used by <a href='http://www.opencaching.com/'>Garmin's Opencaching.com</a>.
|
used by <a href='http://www.opencaching.com/'>Garmin's Opencaching.com</a>.
|
||||||
The element includes information on cache difficulty, ratings, tags and images.
|
The element includes information on cache difficulty, ratings, tags and images.
|
||||||
It is used within Garmin's Geocaching-enabled handheld GPS devices.
|
It is used within Garmin's Geocaching-enabled handheld GPS devices.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='images' default='descrefs:nonspoilers'>
|
<opt name='images' default='descrefs:nonspoilers'>
|
||||||
<p>Which images to include (and how to include them). One of the following values:</p>
|
<p>Which images to include (and how to include them). One of the following values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>none</b> - no images will be included,</li>
|
<li><b>none</b> - no images will be included,</li>
|
||||||
<li><b>descrefs:thumblinks</b> - all images will be included as "thumbnail"
|
<li><b>descrefs:thumblinks</b> - all images will be included as "thumbnail"
|
||||||
<img> references at the end of each cache description, with a
|
<img> references at the end of each cache description, with a
|
||||||
replacement image used for spoilers; the thumbnails are linked to the
|
replacement image used for spoilers; the thumbnails are linked to the
|
||||||
large images,</li>
|
large images,</li>
|
||||||
<li><b>descrefs:nonspoilers</b> - all non-spoiler images will be included
|
<li><b>descrefs:nonspoilers</b> - all non-spoiler images will be included
|
||||||
as <img> references at the end of each cache description,</li>
|
as <img> references at the end of each cache description,</li>
|
||||||
<li><b>descrefs:all</b> - all images will be included (including spoilers)
|
<li><b>descrefs:all</b> - all images will be included (including spoilers)
|
||||||
as <img> references at the end of each cache description,</li>
|
as <img> references at the end of each cache description,</li>
|
||||||
<li><b>ox:all</b> - all images will be included (including spoilers)
|
<li><b>ox:all</b> - all images will be included (including spoilers)
|
||||||
as Garmin's <ox:image> references.</li>
|
as Garmin's <ox:image> references.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Note: When using "descrefs:" mode, remember to set <b>ns_ground</b> to <b>true</b>.
|
<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
|
The default value is "descrefs:nonspoilers" for compatibilty reasons, but for
|
||||||
most applications "descrefs:thumblinks" will be the better choice.</p>
|
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
|
<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
|
include JPEG files along the GPX for this to work properly - see
|
||||||
services/caches/formatters/garmin for more information.</p>
|
services/caches/formatters/garmin for more information.</p>
|
||||||
<p>In the future, more generic ways of including images in GPX files may emerge.</p>
|
<p>In the future, more generic ways of including images in GPX files may emerge.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='attrs' default='desc:text'>
|
<opt name='attrs' default='desc:text'>
|
||||||
<p>This argument controls whether cache attributes are included and how they are included.
|
<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>
|
Pipe-separated list consisting of any set of the following values:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>desc:text</b> - attributes will be listed (in plain-text) within
|
<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>
|
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>
|
<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>
|
elements (<b>ns_ox</b> has to be <b>true</b>),</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>gc:attrs</b> - attributes will be listed as Groundspeak's
|
<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>),
|
<i>groundspeak:attribute</i> elements (<b>ns_ground</b> has to be <b>true</b>),
|
||||||
compatible with Geocaching.com (see the list
|
compatible with Geocaching.com (see the list
|
||||||
<a href='http://www.geocaching.com/about/icons.aspx'>here</a>).</p>
|
<a href='http://www.geocaching.com/about/icons.aspx'>here</a>).</p>
|
||||||
<p>Note that most Opencaching attributes don't have Geocaching.com counterparts.
|
<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>
|
Such attributes cannot be included as gc:attrs and will be ignored.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>gc_ocde:attrs</b> - attributes will be listed as Groundspeak's
|
<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>).
|
<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
|
Opencaching attributes which have no Geocaching.com counterparts will be
|
||||||
included according to an Opencaching.DE convention, using "makeshift IDs"
|
included according to an Opencaching.DE convention, using "makeshift IDs"
|
||||||
which may change in the future.</p>
|
which may change in the future.</p>
|
||||||
<p>Note that this option is supported only by some OC sites. Other sites will
|
<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>
|
handle <b>gc_ocde:attrs</b> in the same way as <b>gc:attrs</b>.</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>If you don't want any attributes to be included, you must set the <b>attrs</b>
|
<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
|
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>
|
trigger the default (<b>desc:text</b>) to be selected, for backward-compatibility.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='protection_areas' default='desc:auto'>
|
<opt name='protection_areas' default='desc:auto'>
|
||||||
<p>This argument controls whether protection area information is included and how
|
<p>This argument controls whether protection area information is included and how
|
||||||
it is included.</p>
|
it is included.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>desc:text</b> - if the cache (probably) is located within one or more
|
<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
|
protection areas, e.g. a nature reserve, a list of the protection areas will
|
||||||
be included in the cache description.</li>
|
be included in the cache description.</li>
|
||||||
<li><b>desc:auto</b> - protection area information may be included in the
|
<li><b>desc:auto</b> - protection area information may be included in the
|
||||||
cache description, depending on the installation.</li>
|
cache description, depending on the installation.</li>
|
||||||
<li><b>none</b> - no protection area information will be included in the
|
<li><b>none</b> - no protection area information will be included in the
|
||||||
GPX data.</li>
|
GPX data.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Note that information on protection areas may be incomplete or outdated
|
<p>Note that information on protection areas may be incomplete or outdated
|
||||||
or completely missing on some installations.</p>
|
or completely missing on some installations.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='trackables' default='none'>
|
<opt name='trackables' default='none'>
|
||||||
<p>This argument controls whether information on trackables is included and how it is included.
|
<p>This argument controls whether information on trackables is included and how it is included.
|
||||||
One of the following values:</p>
|
One of the following values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>none</b> - no trackables-data will be included,</li>
|
<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: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>
|
<li><b>desc:count</b> - total number of trackables will be included (in plain-text) within the cache description.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Note: When using "desc:" mode, remember to set <b>ns_ground</b> to <b>true</b>.</p>
|
<p>Note: When using "desc:" mode, remember to set <b>ns_ground</b> to <b>true</b>.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='recommendations' default='none'>
|
<opt name='recommendations' default='none'>
|
||||||
<p>This argument controls whether information on recommendations is included and how it is included.
|
<p>This argument controls whether information on recommendations is included and how it is included.
|
||||||
One of the following values:</p>
|
One of the following values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>none</b> - no recommendations-info will be included,</li>
|
<li><b>none</b> - no recommendations-info will be included,</li>
|
||||||
<li><b>desc:count</b> - number of recommendations (and founds) will be included
|
<li><b>desc:count</b> - number of recommendations (and founds) will be included
|
||||||
(in plain-text) within the cache description.</li>
|
(in plain-text) within the cache description.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Note: When using "desc:" mode, remember to set <b>ns_ground</b> to <b>true</b>.</p>
|
<p>Note: When using "desc:" mode, remember to set <b>ns_ground</b> to <b>true</b>.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='my_notes' default='none'>
|
<opt name='my_notes' default='none'>
|
||||||
<p>Allows you to include personal user's notes on each cache. This parameter
|
<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
|
takes either <b>none</b> (default value), or pipe separeted list of the
|
||||||
following values:</p>
|
following values:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>desc:text</b> - include personal notes as part of the cache
|
<li><b>desc:text</b> - include personal notes as part of the cache
|
||||||
description.</li>
|
description.</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<p><b>gc:personal_note</b> - include personal notes as
|
<p><b>gc:personal_note</b> - include personal notes as
|
||||||
<groundspeak:personal_note> element (under
|
<groundspeak:personal_note> element (under
|
||||||
<groundspeak:cache> element).</p>
|
<groundspeak:cache> element).</p>
|
||||||
|
|
||||||
<p><b>Warning:</b> This element is not a part of
|
<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
|
<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
|
is a <i>http://www.groundspeak.com/cache/1/0/2</i> schema element. Using
|
||||||
this option will generate formally invalid XML file.</p>
|
this option will generate formally invalid XML file.</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Note: You need to use Level 3 Authentication in order to set it to anything else than "none".</p>
|
<p>Note: You need to use Level 3 Authentication in order to set it to anything else than "none".</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='latest_logs' default='false'>
|
<opt name='latest_logs' default='false'>
|
||||||
<p>Boolean. If <b>true</b> then response will include a couple of
|
<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>
|
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>
|
<p>You <b>must</b> set <b>ns_ground</b> argument to <b>true</b> if you want to use this.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='lpc' default='10'>
|
<opt name='lpc' default='10'>
|
||||||
Log-entries per cache - the number of log entries included in each returned cache.
|
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>
|
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.
|
and <b>latest_logs</b> arguments must be set to <b>true</b> in order for the logs to be included.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='alt_wpts' default='false'>
|
<opt name='alt_wpts' default='false'>
|
||||||
<p>Boolean. If <b>true</b> then we will include additional (alternate) waypoints in the response.
|
<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>
|
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
|
<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
|
waypoints and their geocaches. Please note that not many applications are currently able to
|
||||||
properly understand GSAK metadata.</p>
|
properly understand GSAK metadata.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='mark_found' default='false'>
|
<opt name='mark_found' default='false'>
|
||||||
<p>Boolean. If <b>true</b> then all caches which are already found, will be marked appropriately
|
<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>
|
(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>
|
<p>This field requires you to use the <b>user_uuid</b> parameter (or Level 3 Authentication).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name="user_uuid">
|
<opt name="user_uuid">
|
||||||
<p>User'd ID. Required to mark found caches using <b>Level 1</b> Authentication.</p>
|
<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>
|
<p>If you use <b>Level 3</b> Authentication, you shouldn't use this parameter. Or, to be exact:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>user_uuid</b> will be extracted from the Access Token you use. You don't have to provide it.</li>
|
<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
|
<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>
|
will respond with HTTP 400 error.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</opt>
|
</opt>
|
||||||
<returns>
|
<opt name="location_source" default='default-coords'>
|
||||||
<p>GPX file. All invalid cache codes will be skipped without any notice!</p>
|
<p>If you supply a value, then it must be prefixed with <i>alt_wpt:</i>,
|
||||||
</returns>
|
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>
|
</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://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
|
http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||||
">
|
">
|
||||||
<name><?= $vars['installation']['site_name'] ?> Geocache Search Results</name>
|
<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>
|
<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>
|
<author><?= $vars['installation']['site_name'] ?></author>
|
||||||
<url><?= $vars['installation']['site_url'] ?></url>
|
<url><?= $vars['installation']['site_url'] ?></url>
|
||||||
<urlname><?= $vars['installation']['site_name'] ?></urlname>
|
<urlname><?= $vars['installation']['site_name'] ?></urlname>
|
||||||
<time><?= date('c') ?></time>
|
<time><?= date('c') ?></time>
|
||||||
<? foreach ($vars['caches'] as $c) { ?>
|
<? 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']); ?>
|
||||||
<? list($lat, $lon) = explode("|", $c['location']); ?>
|
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
||||||
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
<time><?= $c['date_created'] ?></time>
|
||||||
<time><?= $c['date_created'] ?></time>
|
<name><?= $c['code'] ?></name>
|
||||||
<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>
|
||||||
<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>
|
||||||
<url><?= $c['url'] ?></url>
|
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
||||||
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
<sym><?= ($vars['mark_found'] && $c['is_found']) ? "Geocache Found" : "Geocache" ?></sym>
|
||||||
<sym><?= ($vars['mark_found'] && $c['is_found']) ? "Geocache Found" : "Geocache" ?></sym>
|
<type>Geocache|<?= $vars['cache_GPX_types'][$c['type']] ?></type>
|
||||||
<type>Geocache|<?= $vars['cache_GPX_types'][$c['type']] ?></type>
|
<? if ($vars['ns_ground']) { /* Does user want us to include Groundspeak's <cache> element? */ ?>
|
||||||
<? 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: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:name><?= Okapi::xmlescape($c['name']) ?></groundspeak:name>
|
<groundspeak:placed_by><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:placed_by>
|
||||||
<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: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:type><?= $vars['cache_GPX_types'][$c['type']] ?></groundspeak:type>
|
<groundspeak:container><?= $vars['cache_GPX_sizes'][$c['size2']] ?></groundspeak:container>
|
||||||
<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? */ ?>
|
||||||
<? if ($vars['gc_attrs'] || $vars['gc_ocde_attrs']) { /* Does user want us to include groundspeak:attributes? */ ?>
|
<groundspeak:attributes>
|
||||||
<groundspeak:attributes>
|
<?
|
||||||
<?
|
foreach ($c['gc_attrs'] as $gc_id => $gc_attr) {
|
||||||
foreach ($c['gc_attrs'] as $gc_id => $gc_attr) {
|
print "<groundspeak:attribute id=\"".$gc_id."\" ";
|
||||||
print "<groundspeak:attribute id=\"".$gc_id."\" ";
|
print "inc=\"".$gc_attr['inc']."\">";
|
||||||
print "inc=\"".$gc_attr['inc']."\">";
|
print Okapi::xmlescape($gc_attr['name']);
|
||||||
print Okapi::xmlescape($gc_attr['name']);
|
print "</groundspeak:attribute>";
|
||||||
print "</groundspeak:attribute>";
|
}
|
||||||
}
|
?>
|
||||||
?>
|
</groundspeak:attributes>
|
||||||
</groundspeak:attributes>
|
<? } ?>
|
||||||
<? } ?>
|
<groundspeak:difficulty><?= $c['difficulty'] ?></groundspeak:difficulty>
|
||||||
<groundspeak:difficulty><?= $c['difficulty'] ?></groundspeak:difficulty>
|
<groundspeak:terrain><?= $c['terrain'] ?></groundspeak:terrain>
|
||||||
<groundspeak:terrain><?= $c['terrain'] ?></groundspeak:terrain>
|
<? if ($c['short_description']) { ?>
|
||||||
<groundspeak:long_description html="True">
|
<groundspeak:short_description html="False"><?= Okapi::xmlescape($c['short_description']) ?></groundspeak:short_description>
|
||||||
<p>
|
<? } ?>
|
||||||
<a href="<?= $c['url'] ?>"><?= Okapi::xmlescape($c['name']) ?></a>
|
<groundspeak:long_description html="True">
|
||||||
<?= _("hidden by") ?> <a href='<?= $c['owner']['profile_url'] ?>'><?= Okapi::xmlescape($c['owner']['username']) ?></a><br/>
|
<? if (isset($c['warning_prefix'])) { ?>
|
||||||
<? if ($vars['recommendations'] == 'desc:count') { /* Does user want us to include recommendations count? */ ?>
|
<p style='font-size: 120%'><?= Okapi::xmlescape($c['warning_prefix']) ?></p>
|
||||||
<?= sprintf(ngettext("%d recommendation", "%d recommendations", $c['recommendations']), $c['recommendations']) ?>
|
<? } ?>
|
||||||
(<?= sprintf(ngettext("found %d time", "found %d times", $c['founds']), $c['founds']) ?>).
|
<p>
|
||||||
<? } ?>
|
<a href="<?= $c['url'] ?>"><?= Okapi::xmlescape($c['name']) ?></a>
|
||||||
<? if ($vars['trackables'] == 'desc:count') { /* Does user want us to include trackables count? */ ?>
|
<?= _("hidden by") ?> <a href='<?= $c['owner']['profile_url'] ?>'><?= Okapi::xmlescape($c['owner']['username']) ?></a><br/>
|
||||||
<?= sprintf(ngettext("%d trackable", "%d trackables", $c['trackables_count']), $c['trackables_count']) ?>.
|
<? if ($vars['recommendations'] == 'desc:count') { /* Does user want us to include recommendations count? */ ?>
|
||||||
<? } ?>
|
<?= sprintf(ngettext("%d recommendation", "%d recommendations", $c['recommendations']), $c['recommendations']) ?>
|
||||||
</p>
|
(<?= sprintf(ngettext("found %d time", "found %d times", $c['founds']), $c['founds']) ?>).
|
||||||
<? 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 ($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? */ ?>
|
<? if (in_array('desc:text', $vars['attrs']) && count($c['attrnames']) > 0) { /* Does user want us to include attributes? */ ?>
|
||||||
<p><?= _("Attributes") ?>:</p>
|
<p><?= _("Attributes") ?>:</p>
|
||||||
<ul><li><?= implode("</li><li>", $c['attrnames']) ?></li></ul>
|
<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? */ ?>
|
<? if ($vars['trackables'] == 'desc:list' && count($c['trackables']) > 0) { /* Does user want us to include trackables list? */ ?>
|
||||||
<p><?= _("Trackables") ?>:</p>
|
<p><?= _("Trackables") ?>:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<? foreach ($c['trackables'] as $t) { ?>
|
<? foreach ($c['trackables'] as $t) { ?>
|
||||||
<li><a href='<?= Okapi::xmlescape($t['url']) ?>'><?= Okapi::xmlescape($t['name']) ?></a> (<?= $t['code'] ?>)</li>
|
<li><a href='<?= Okapi::xmlescape($t['url']) ?>'><?= Okapi::xmlescape($t['name']) ?></a> (<?= $t['code'] ?>)</li>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</ul>
|
</ul>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<?= Okapi::xmlescape($c['description']) ?>
|
<?= 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 ((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") { ?>
|
if ($vars['images'] == "descrefs:thumblinks") { ?>
|
||||||
<h2><?= _("Images") ?> (<?= count($c['images']) ?>)</h2>
|
<h2><?= _("Images") ?> (<?= count($c['images']) ?>)</h2>
|
||||||
<div>
|
<div>
|
||||||
<? foreach ($c['images'] as $img) { ?>
|
<? 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>
|
<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>
|
<?= Okapi::xmlescape($img['caption']) ?></div>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</div>
|
</div>
|
||||||
<? } else {
|
<? } else {
|
||||||
# We will split images into two subcategories: spoilers and nonspoilers.
|
# We will split images into two subcategories: spoilers and nonspoilers.
|
||||||
$spoilers = array();
|
$spoilers = array();
|
||||||
$nonspoilers = array();
|
$nonspoilers = array();
|
||||||
foreach ($c['images'] as $img)
|
foreach ($c['images'] as $img)
|
||||||
if ($img['is_spoiler']) $spoilers[] = $img;
|
if ($img['is_spoiler']) $spoilers[] = $img;
|
||||||
else $nonspoilers[] = $img;
|
else $nonspoilers[] = $img;
|
||||||
?>
|
?>
|
||||||
<? if (count($nonspoilers) > 0) { ?>
|
<? if (count($nonspoilers) > 0) { ?>
|
||||||
<h2><?= _("Images") ?> (<?= count($nonspoilers) ?>)</h2>
|
<h2><?= _("Images") ?> (<?= count($nonspoilers) ?>)</h2>
|
||||||
<? foreach ($nonspoilers as $img) { ?>
|
<? foreach ($nonspoilers as $img) { ?>
|
||||||
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
||||||
<?= Okapi::xmlescape($img['caption']) ?></p>
|
<?= Okapi::xmlescape($img['caption']) ?></p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if (count($spoilers) > 0 && $vars['images'] == 'descrefs:all') { ?>
|
<? if (count($spoilers) > 0 && $vars['images'] == 'descrefs:all') { ?>
|
||||||
<h2><?= _("Spoilers") ?> (<?= count($spoilers) ?>)</h2>
|
<h2><?= _("Spoilers") ?> (<?= count($spoilers) ?>)</h2>
|
||||||
<? foreach ($spoilers as $img) { ?>
|
<? foreach ($spoilers as $img) { ?>
|
||||||
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
||||||
<?= Okapi::xmlescape($img['caption']) ?></p>
|
<?= Okapi::xmlescape($img['caption']) ?></p>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if ((strpos($vars['images'], "ox:") === 0) && count($c['images']) > 0) { /* Include image descriptions (for ox:image numbers)? */ ?>
|
<? if ((strpos($vars['images'], "ox:") === 0) && count($c['images']) > 0) { /* Include image descriptions (for ox:image numbers)? */ ?>
|
||||||
<p><?= _("Image descriptions") ?>:</p>
|
<p><?= _("Image descriptions") ?>:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<? foreach ($c['images'] as $no => $img) { ?>
|
<? foreach ($c['images'] as $no => $img) { ?>
|
||||||
<li><?= $img['unique_caption'] ?>. <?= Okapi::xmlescape($img['caption']) ?></li>
|
<li><?= $img['unique_caption'] ?>. <?= Okapi::xmlescape($img['caption']) ?></li>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</ul>
|
</ul>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if ($vars['protection_areas'] == 'desc:text' && count($c['protection_areas'])) { ?>
|
<? if ($vars['protection_areas'] == 'desc:text' && count($c['protection_areas'])) { ?>
|
||||||
<p><?= _("The cache probably is located in the following protection areas:") ?></p>
|
<p><?= _("The cache probably is located in the following protection areas:") ?></p>
|
||||||
<ul>
|
<ul>
|
||||||
<? foreach($c['protection_areas'] as $protection_area) { ?>
|
<? foreach($c['protection_areas'] as $protection_area) { ?>
|
||||||
<li><?= Okapi::xmlescape($protection_area['type'])." - ".Okapi::xmlescape($protection_area['name']) ?></li>
|
<li><?= Okapi::xmlescape($protection_area['type'])." - ".Okapi::xmlescape($protection_area['name']) ?></li>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</ul;>
|
</ul;>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</groundspeak:long_description>
|
</groundspeak:long_description>
|
||||||
<groundspeak:encoded_hints><?= Okapi::xmlescape($c['hint2']) ?></groundspeak:encoded_hints>
|
<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 */ ?>
|
<? 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>
|
<groundspeak:personal_note><?= Okapi::xmlescape($c['my_notes']) ?></groundspeak:personal_note>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if ($vars['latest_logs']) { /* Does user want us to include latest log entries? */ ?>
|
<? if ($vars['latest_logs']) { /* Does user want us to include latest log entries? */ ?>
|
||||||
<groundspeak:logs>
|
<groundspeak:logs>
|
||||||
<? foreach ($c['latest_logs'] as $log) { ?>
|
<? foreach ($c['latest_logs'] as $log) { ?>
|
||||||
<groundspeak:log id="<?= $log['internal_id'] ?>">
|
<groundspeak:log id="<?= $log['internal_id'] ?>">
|
||||||
<groundspeak:date><?= $log['date'] ?></groundspeak:date>
|
<groundspeak:date><?= $log['date'] ?></groundspeak:date>
|
||||||
<groundspeak:type><?= $log['type'] ?></groundspeak:type>
|
<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: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:text encoded="False"><?= $log['was_recommended'] ? "(*) ": "" ?><?= Okapi::xmlescape($log['comment']) ?></groundspeak:text>
|
||||||
</groundspeak:log>
|
</groundspeak:log>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</groundspeak:logs>
|
</groundspeak:logs>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? /* groundspeak:travelbugs - does it actually DO anything? WRTODO */ ?>
|
<? /* groundspeak:travelbugs - does it actually DO anything? WRTODO */ ?>
|
||||||
</groundspeak:cache>
|
</groundspeak:cache>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? if ($vars['ns_ox']) { /* Does user want us to include Garmin's <opencaching> element? */ ?>
|
<? 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:opencaching xmlns:ox="http://www.opencaching.com/xmlschemas/opencaching/1/0">
|
||||||
<ox:ratings>
|
<ox:ratings>
|
||||||
<? if ($c['rating'] !== null) { ?><ox:awesomeness><?= $c['rating'] ?></ox:awesomeness><? } ?>
|
<? if ($c['rating'] !== null) { ?><ox:awesomeness><?= $c['rating'] ?></ox:awesomeness><? } ?>
|
||||||
<ox:difficulty><?= $c['difficulty'] ?></ox:difficulty>
|
<ox:difficulty><?= $c['difficulty'] ?></ox:difficulty>
|
||||||
<? if ($c['oxsize'] !== null) { ?><ox:size><?= $c['oxsize'] ?></ox:size><? } ?>
|
<? if ($c['oxsize'] !== null) { ?><ox:size><?= $c['oxsize'] ?></ox:size><? } ?>
|
||||||
<ox:terrain><?= $c['terrain'] ?></ox:terrain>
|
<ox:terrain><?= $c['terrain'] ?></ox:terrain>
|
||||||
</ox:ratings>
|
</ox:ratings>
|
||||||
<? if (in_array('ox:tags', $vars['attrs']) && count($c['attrnames']) > 0) { /* Does user want us to include ox:tags? */ ?>
|
<? 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>
|
<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? */ ?>
|
<? if ((strpos($vars['images'], "ox:") === 0) && count($c['images']) > 0) { /* Does user want us to include ox:image references? */ ?>
|
||||||
<ox:images>
|
<ox:images>
|
||||||
<? foreach ($c['images'] as $no => $img) { ?>
|
<? foreach ($c['images'] as $no => $img) { ?>
|
||||||
<ox:image>
|
<ox:image>
|
||||||
<ox:name><?= $img['unique_caption'] ?>.jpg</ox:name>
|
<ox:name><?= $img['unique_caption'] ?>.jpg</ox:name>
|
||||||
<ox:size>0</ox:size>
|
<ox:size>0</ox:size>
|
||||||
<ox:required>false</ox:required>
|
<ox:required>false</ox:required>
|
||||||
<ox:spoiler><?= ($img['is_spoiler'] ? "true" : "false") ?></ox:spoiler>
|
<ox:spoiler><?= ($img['is_spoiler'] ? "true" : "false") ?></ox:spoiler>
|
||||||
</ox:image>
|
</ox:image>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</ox:images>
|
</ox:images>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</ox:opencaching>
|
</ox:opencaching>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</wpt>
|
</wpt>
|
||||||
<? if ($vars['alt_wpts']) { ?>
|
<? if ($vars['alt_wpts']) { ?>
|
||||||
<? foreach ($c['alt_wpts'] as $wpt) { ?>
|
<? foreach ($c['alt_wpts'] as $wpt) { ?>
|
||||||
<? list($lat, $lon) = explode("|", $wpt['location']); ?>
|
<? list($lat, $lon) = explode("|", $wpt['location']); ?>
|
||||||
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
||||||
<time><?= $c['date_created'] ?></time>
|
<time><?= $c['date_created'] ?></time>
|
||||||
<name><?= Okapi::xmlescape($wpt['name']) ?></name>
|
<name><?= Okapi::xmlescape($wpt['name']) ?></name>
|
||||||
<cmt><?= Okapi::xmlescape($wpt['description']) ?></cmt>
|
<cmt><?= Okapi::xmlescape($wpt['description']) ?></cmt>
|
||||||
<desc><?= Okapi::xmlescape($wpt['type_name']) ?></desc>
|
<desc><?= Okapi::xmlescape($wpt['type_name']) ?></desc>
|
||||||
<url><?= $c['url'] ?></url>
|
<url><?= $c['url'] ?></url>
|
||||||
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
||||||
<sym><?= $wpt['sym'] ?></sym>
|
<sym><?= $wpt['sym'] ?></sym>
|
||||||
<type>Waypoint|<?= $wpt['sym'] ?></type>
|
<type>Waypoint|<?= $wpt['sym'] ?></type>
|
||||||
<? if ($vars['ns_gsak']) { ?>
|
<? if ($vars['ns_gsak']) { ?>
|
||||||
<gsak:wptExtension xmlns:gsak="http://www.gsak.net/xmlv1/5">
|
<gsak:wptExtension xmlns:gsak="http://www.gsak.net/xmlv1/5">
|
||||||
<gsak:Parent><?= $c['code'] ?></gsak:Parent>
|
<gsak:Parent><?= $c['code'] ?></gsak:Parent>
|
||||||
</gsak:wptExtension>
|
</gsak:wptExtension>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</wpt>
|
</wpt>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
<? } ?>
|
<? } ?>
|
||||||
</gpx>
|
</gpx>
|
||||||
|
|||||||
@@ -12,51 +12,51 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$cache_code = $request->get_parameter('cache_code');
|
$cache_code = $request->get_parameter('cache_code');
|
||||||
if (!$cache_code) throw new ParamMissing('cache_code');
|
if (!$cache_code) throw new ParamMissing('cache_code');
|
||||||
if (strpos($cache_code, "|") !== false) throw new InvalidParam('cache_code');
|
if (strpos($cache_code, "|") !== false) throw new InvalidParam('cache_code');
|
||||||
$langpref = $request->get_parameter('langpref');
|
$langpref = $request->get_parameter('langpref');
|
||||||
if (!$langpref) $langpref = "en";
|
if (!$langpref) $langpref = "en";
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields) $fields = "code|name|location|type|status";
|
if (!$fields) $fields = "code|name|location|type|status";
|
||||||
$log_fields = $request->get_parameter('log_fields');
|
$log_fields = $request->get_parameter('log_fields');
|
||||||
if (!$log_fields) $log_fields = "uuid|date|user|type|comment";
|
if (!$log_fields) $log_fields = "uuid|date|user|type|comment";
|
||||||
$lpc = $request->get_parameter('lpc');
|
$lpc = $request->get_parameter('lpc');
|
||||||
if (!$lpc) $lpc = 10;
|
if (!$lpc) $lpc = 10;
|
||||||
$attribution_append = $request->get_parameter('attribution_append');
|
$attribution_append = $request->get_parameter('attribution_append');
|
||||||
if (!$attribution_append) $attribution_append = 'full';
|
if (!$attribution_append) $attribution_append = 'full';
|
||||||
$params = array(
|
$params = array(
|
||||||
'cache_codes' => $cache_code,
|
'cache_codes' => $cache_code,
|
||||||
'langpref' => $langpref,
|
'langpref' => $langpref,
|
||||||
'fields' => $fields,
|
'fields' => $fields,
|
||||||
'attribution_append' => $attribution_append,
|
'attribution_append' => $attribution_append,
|
||||||
'lpc' => $lpc,
|
'lpc' => $lpc,
|
||||||
'log_fields' => $log_fields
|
'log_fields' => $log_fields
|
||||||
);
|
);
|
||||||
$my_location = $request->get_parameter('my_location');
|
$my_location = $request->get_parameter('my_location');
|
||||||
if ($my_location)
|
if ($my_location)
|
||||||
$params['my_location'] = $my_location;
|
$params['my_location'] = $my_location;
|
||||||
$user_uuid = $request->get_parameter('user_uuid');
|
$user_uuid = $request->get_parameter('user_uuid');
|
||||||
if ($user_uuid)
|
if ($user_uuid)
|
||||||
$params['user_uuid'] = $user_uuid;
|
$params['user_uuid'] = $user_uuid;
|
||||||
|
|
||||||
# There's no need to validate the fields/lpc parameters as the 'geocaches'
|
# 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).
|
# method does this (it will raise a proper exception on invalid values).
|
||||||
|
|
||||||
$results = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
$results = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, $params));
|
$request->consumer, $request->token, $params));
|
||||||
$result = $results[$cache_code];
|
$result = $results[$cache_code];
|
||||||
if ($result === null)
|
if ($result === null)
|
||||||
throw new InvalidParam('cache_code', "This cache does not exist.");
|
throw new InvalidParam('cache_code', "This cache does not exist.");
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,413 +1,440 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve information on a single geocache</brief>
|
<brief>Retrieve information on a single geocache</brief>
|
||||||
<issue-id>19</issue-id>
|
<issue-id>19</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Retrieve information on a single geocache.</p>
|
<p>Retrieve information on a single geocache.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='cache_code'>Unique code of the geocache</req>
|
<req name='cache_code'>Unique code of the geocache</req>
|
||||||
<opt name='langpref' default='en'>
|
<opt name='langpref' default='en'>
|
||||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
<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
|
order of preference in which language will be chosen for fields like
|
||||||
<b>name</b> and <b>description</b>.</p>
|
<b>name</b> and <b>description</b>.</p>
|
||||||
<p>Please note, that you may also access caches' descriptions in all
|
<p>Please note, that you may also access caches' descriptions in all
|
||||||
available languages. If you want to do this, you should use fields
|
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>names</b>, <b>descriptions</b> (etc.) instead of <b>name</b> and
|
||||||
<b>description</b> (etc.).</p>
|
<b>description</b> (etc.).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='fields' default='code|name|location|type|status'>
|
<opt name='fields' default='code|name|location|type|status'>
|
||||||
<p>Pipe-separated list of field names which you are interested with.
|
<p>Pipe-separated list of field names which you are interested with.
|
||||||
Selected fields will be included in the response. See below for the
|
Selected fields will be included in the response. See below for the
|
||||||
list of available fields.</p>
|
list of available fields.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='attribution_append' default='full'>
|
<opt name='attribution_append' default='full'>
|
||||||
<p>By default, OKAPI appends the value of <b>attribution_note</b> field to all the
|
<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,
|
cache descriptions. If you would like to display the attribution note separately,
|
||||||
you may use this parameter. Use one of the following values:</p>
|
you may use this parameter. Use one of the following values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<b>full</b> - OKAPI will append the attribution note to the descriptions of the
|
<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
|
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
|
(i.e. each value in <b>descriptions</b> may contain attribution notes in
|
||||||
a different language).
|
a different language).
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>none</b> - OKAPI will not append the attribution note to geocache
|
<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
|
descriptions. You will use the <b>attribution_note</b> instead (which depends
|
||||||
on the <b>langpref</b> parameter).</p>
|
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>
|
|
||||||
|
|
||||||
<p>The value of <b>preview_image</b> is either <b>null</b> or a dictionary describing
|
<p><b>Important note:</b> You are still <b>required</b> to display the
|
||||||
an image. The structure of this dictionary is the same as of a single entry on
|
<b>attribution_note</b> field in some other way.</p>
|
||||||
the <b>images</b> list described above.</p>
|
</li>
|
||||||
</li>
|
<li>
|
||||||
<li>
|
<b>static</b> - OKAPI will append a "static" attribution note to the descriptions
|
||||||
<p><b>attr_acodes</b> - unordered list of OKAPI geocache-attribute IDs (A-codes) with
|
of the geocache. This might equal the "full" attribution note, but not necessarilly,
|
||||||
which the cache was tagged. Use the <b>attrs</b> module to retrieve information on
|
since the "full" note may contain a current date
|
||||||
these attributes.</p>
|
(<a href='https://code.google.com/p/opencaching-api/issues/detail?id=178'>why?</a>),
|
||||||
</li>
|
and the "static" note will not. This is implemented primarily for internal use
|
||||||
<li>
|
(i.e. the replicate module). Usually you should not use it, because on some
|
||||||
<b>attrnames</b> - if you don't want to dig into <b>attr_acodes</b> just now, then
|
installations the static note will not be sufficient to meet the data license
|
||||||
you can use these as a simple alternative. <b>attrnames</b> is an unordered list of
|
requirements.
|
||||||
names of the attributes with which the cache was tagged; the language will be
|
</li>
|
||||||
selected based on the <b>langpref</b> parameter.
|
</ul>
|
||||||
</li>
|
</opt>
|
||||||
<li>
|
<opt name='lpc' default='10'>
|
||||||
<p><b>attribution_note</b> - the proper attribution note for the cache listing according
|
Log-entries per cache - the number of logs returned in the <b>latest_logs</b> field.
|
||||||
to the local OC site's Data License. By default, this note is also appended to geocache
|
This should be an integer or a special "all" value. Please note, that you must include
|
||||||
descriptions (see the <b>attribution_append</b> parameter).</p>
|
the <b>latest_logs</b> field in <b>fields</b> in order to see the log entries.
|
||||||
</li>
|
</opt>
|
||||||
<li>
|
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
||||||
<p><b>latest_logs</b> - a couple of latest log entries in the cache.
|
Pipe-separated list of log fields to include in the <b>latest_logs</b> field.
|
||||||
The format is the same as the one returned by the services/logs/logs method.</p>
|
For valid field names, see <b>logs/entry</b> method.
|
||||||
<p>Notice: The number of logs returned can be set with the <b>lpc</b> option.</p>
|
</opt>
|
||||||
</li>
|
<opt name='my_location'>
|
||||||
<li>
|
<p>The reference point for cache distance and bearing calculation (typically - the user's location),
|
||||||
<p><b>my_notes</b> - user's notes on the cache, in plain-text, or <b>null</b>
|
in the "lat|lon" format. This parameter is required when accessing <b>distance</b> and/or <b>bearing</b>
|
||||||
if user hadn't defined any notes.</p>
|
fields.</p>
|
||||||
<p>This field requires you to use the <b>Level 3</b> Authentication.</p>
|
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||||
</li>
|
longitudes in the eastern hemisphere (and negative for southern and
|
||||||
<li><b>trackables_count</b> - a total number of trackables hidden within the cache.</li>
|
western hemispheres accordingly). These are full degrees with a dot
|
||||||
<li>
|
as a decimal point (ex. "54.3|22.3").</p>
|
||||||
<p><b>trackables</b> - list of dictionaries, each dictionary represents one
|
</opt>
|
||||||
trackable hidden within the cache container; each dictionary has the
|
<opt name="user_uuid">
|
||||||
following structure:</p>
|
<p>User'd ID. Required to access fields like <b>is_found</b> using <b>Level 1</b> Authentication.</p>
|
||||||
<ul>
|
<p>Please note that if you want to access private fields (like <b>my_notes</b>), then
|
||||||
<li><b>code</b> - code of the trackable,</li>
|
this parameter won't help you. You have to use <b>Level 3</b> Authentication instead.</p>
|
||||||
<li><b>name</b> - plain text name of the trackable,</li>
|
<p>If you use <b>Level 3</b> Authentication, you shouldn't use this parameter. Or, to be exact:</p>
|
||||||
<li><b>url</b> - trackable's own webpage address <b>or null</b>, if OKAPI
|
<ul>
|
||||||
cannot automatically determine this address.</li>
|
<li><b>user_uuid</b> will be extracted from the Access Token you use. You don't have to provide it.</li>
|
||||||
</ul>
|
<li>If you provide <b>user_uuid</b>, then it HAS TO match your Access Token. If it doesn't, OKAPI
|
||||||
</li>
|
will respond with HTTP 400 error.</li>
|
||||||
<li>
|
</ul>
|
||||||
<p><b>alt_wpts</b> - list of alternate/additional waypoints associated
|
</opt>
|
||||||
with this geocache. Each item is a dictionary of the following structure:</p>
|
<common-format-params/>
|
||||||
<ul>
|
<returns>
|
||||||
<li><b>name</b> - plain-text, short, unique "codename" for the waypoint,</li>
|
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||||
<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>For example, for <i>geocache?cache_code=OP3D96&fields=type</i>
|
<ul>
|
||||||
query, the result might look something link this:</p>
|
<li><b>code</b> - unique Opencaching code of the geocache,</li>
|
||||||
<pre>{"type": "Traditional"}</pre>
|
<li><b>name</b> - name of the geocache,</li>
|
||||||
<p>If given cache code does not exist, the method will
|
<li><b>names</b> - a dictionary (language code => plain-text string) of
|
||||||
respond with an HTTP 400 error.</p>
|
names of the geocache (at this time, there will be only one language,
|
||||||
</returns>
|
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>
|
</xml>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,51 +1,54 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve information on multiple geocaches</brief>
|
<brief>Retrieve information on multiple geocaches</brief>
|
||||||
<issue-id>20</issue-id>
|
<issue-id>20</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method works like the services/caches/geocache method, but works
|
<p>This method works like the services/caches/geocache method, but works
|
||||||
with multiple geocaches (instead of only one).</p>
|
with multiple geocaches (instead of only one).</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='cache_codes'>
|
<req name='cache_codes'>
|
||||||
<p>Pipe-separated list of cache cache codes. These represent the
|
<p>Pipe-separated list of cache cache codes. These represent the
|
||||||
geocaches you are interested in. No more than 500 codes are allowed.
|
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
|
Unlike in the "geocache" method, this CAN be an empty string (it will
|
||||||
result in an empty, but valid, response).</p>
|
result in an empty, but valid, response).</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='langpref' default='en'>
|
<opt name='langpref' default='en'>
|
||||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
<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
|
order of preference in which language will be chosen for fields like
|
||||||
<b>name</b> and <b>description</b>.</p>
|
<b>name</b> and <b>description</b>.</p>
|
||||||
<p>Please note, that you may also access caches' descriptions in all
|
<p>Please note, that you may also access caches' descriptions in all
|
||||||
available languages. If you want to do this, you should use fields
|
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>names</b>, <b>descriptions</b> (etc.) instead of <b>name</b> and
|
||||||
<b>description</b> (etc.).</p>
|
<b>description</b> (etc.).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='fields' default='code|name|location|type|status'>
|
<opt name='fields' default='code|name|location|type|status'>
|
||||||
<p>Same as in the services/caches/geocache method. Pipe-separated list
|
<p>Same as in the services/caches/geocache method. Pipe-separated list
|
||||||
of field names which you are interested with.
|
of field names which you are interested with.
|
||||||
See services/caches/geocache method for a list available values.</p>
|
See services/caches/geocache method for a list available values.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='attribution_append' default='full'>
|
<opt name='attribution_append' default='full'>
|
||||||
<p>Same as in the services/caches/geocache method.</p>
|
<p>Same as in the services/caches/geocache method.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='lpc' default='10'>
|
<opt name='lpc' default='10'>
|
||||||
Same as in the services/caches/geocache method.
|
Same as in the services/caches/geocache method.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
||||||
Same as in the services/caches/geocache method.
|
Same as in the services/caches/geocache method.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='user_uuid'>
|
<opt name='my_location'>
|
||||||
Same as in the services/caches/geocache method.
|
Same as in the services/caches/geocache method.
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<opt name='user_uuid'>
|
||||||
<returns>
|
Same as in the services/caches/geocache method.
|
||||||
<p>A dictionary. Cache codes you provide will be mapped to dictionary keys,
|
</opt>
|
||||||
and each value will be a dictionary of fields you have selected.</p>
|
<common-format-params/>
|
||||||
<p>For example, for <i>geocaches?cache_codes=OP3D96|OC124&fields=type</i>
|
<returns>
|
||||||
query, the result might look something link this:</p>
|
<p>A dictionary. Cache codes you provide will be mapped to dictionary keys,
|
||||||
<pre>{"OP3D96": {"type": "Traditional"}, "OC124": null}</pre>
|
and each value will be a dictionary of fields you have selected.</p>
|
||||||
<p>Value of <b>null</b> means that the given cache haven't been found.
|
<p>For example, for <i>geocaches?cache_codes=OP3D96|OC124&fields=type</i>
|
||||||
(This behavior is different than in the services/caches/geocache method, which
|
query, the result might look something link this:</p>
|
||||||
responds with an HTTP 400 error in such case.)</p>
|
<pre>{"OP3D96": {"type": "Traditional"}, "OC124": null}</pre>
|
||||||
</returns>
|
<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>
|
</xml>
|
||||||
@@ -23,230 +23,246 @@ require_once 'tiletree.inc.php';
|
|||||||
|
|
||||||
class ReplicateListener
|
class ReplicateListener
|
||||||
{
|
{
|
||||||
public static function receive($changelog)
|
public static function receive($changelog)
|
||||||
{
|
{
|
||||||
# This will be called every time new items arrive from replicate module's
|
# This will be called every time new items arrive from replicate module's
|
||||||
# changelog. The format of $changelog is described in the replicate module
|
# changelog. The format of $changelog is described in the replicate module
|
||||||
# (NOT the entire response, just the "changelog" key).
|
# (NOT the entire response, just the "changelog" key).
|
||||||
|
|
||||||
foreach ($changelog as $c)
|
foreach ($changelog as $c)
|
||||||
{
|
{
|
||||||
if ($c['object_type'] == 'geocache')
|
if ($c['object_type'] == 'geocache')
|
||||||
{
|
{
|
||||||
if ($c['change_type'] == 'replace')
|
if ($c['change_type'] == 'replace')
|
||||||
self::handle_geocache_replace($c);
|
self::handle_geocache_replace($c);
|
||||||
else
|
else
|
||||||
self::handle_geocache_delete($c);
|
self::handle_geocache_delete($c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function reset($mail_admins = true)
|
public static function reset($mail_admins = true)
|
||||||
{
|
{
|
||||||
# This will be called when there are "too many" entries in the changelog
|
# 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.
|
# 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.
|
# 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_status");
|
||||||
Db::execute("delete from okapi_tile_caches");
|
Db::execute("delete from okapi_tile_caches");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function handle_geocache_replace($c)
|
private static function handle_geocache_replace($c)
|
||||||
{
|
{
|
||||||
# Check if any relevant geocache attributes have changed.
|
# Check if any relevant geocache attributes have changed.
|
||||||
# We will pick up "our" copy of the cache from zero-zoom level.
|
# We will pick up "our" copy of the cache from zero-zoom level.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$cache = OkapiServiceRunner::call("services/caches/geocache", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
$cache = OkapiServiceRunner::call("services/caches/geocache", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
||||||
'cache_code' => $c['object_key']['code'],
|
'cache_code' => $c['object_key']['code'],
|
||||||
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
||||||
)));
|
)));
|
||||||
} catch (InvalidParam $e) {
|
} catch (InvalidParam $e) {
|
||||||
# Unprobable, but possible. Ignore changelog entry.
|
# Unprobable, but possible. Ignore changelog entry.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$theirs = TileTree::generate_short_row($cache);
|
# Fetch our copy of the 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... ;)
|
|
||||||
|
|
||||||
self::add_geocache_to_cached_tiles($theirs);
|
$ours = mysql_fetch_row(Db::query("
|
||||||
}
|
select cache_id, z21x, z21y, status, type, rating, flags
|
||||||
elseif (($ours[1] != $theirs[1]) || ($ours[2] != $theirs[2])) # z21x & z21y fields
|
from okapi_tile_caches
|
||||||
{
|
where
|
||||||
# Location changed.
|
z=0
|
||||||
|
and cache_id = '".mysql_real_escape_string($cache['internal_id'])."'
|
||||||
|
"));
|
||||||
|
|
||||||
self::remove_geocache_from_cached_tiles($ours[0]);
|
# Caches near the poles caused our computations to break here. We will
|
||||||
self::add_geocache_to_cached_tiles($theirs);
|
# ignore such caches!
|
||||||
}
|
|
||||||
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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function remove_geocache_from_cached_tiles($cache_id)
|
list($lat, $lon) = explode("|", $cache['location']);
|
||||||
{
|
if ((floatval($lat) >= 89.99) || (floatval($lat) <= -89.99)) {
|
||||||
# Simply remove all traces of this geocache from all tiles.
|
if ($ours) {
|
||||||
# This includes all references along tiles' borders, etc.
|
self::remove_geocache_from_cached_tiles($ours[0]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Db::execute("
|
# Compute the new row for okapi_tile_caches. Compare with the old one.
|
||||||
delete from okapi_tile_caches
|
|
||||||
where cache_id = '".mysql_real_escape_string($cache_id)."'
|
|
||||||
");
|
|
||||||
|
|
||||||
# Note, that after this operation, okapi_tile_status may be out-of-date.
|
$theirs = TileTree::generate_short_row($cache);
|
||||||
# There might exist some rows with status==2, but they should be in status==1.
|
if (!$ours)
|
||||||
# Currently, we can ignore this, because status==1 is just a shortcut to
|
{
|
||||||
# avoid making unnecessary queries.
|
# Aaah, a new geocache! How nice... ;)
|
||||||
}
|
|
||||||
|
|
||||||
private static function add_geocache_to_cached_tiles(&$row)
|
self::add_geocache_to_cached_tiles($theirs);
|
||||||
{
|
}
|
||||||
# This one is the most complicated. We need to identify all tiles
|
elseif (($ours[1] != $theirs[1]) || ($ours[2] != $theirs[2])) # z21x & z21y fields
|
||||||
# where the cache should be present. This include 22 obvious "exact match"
|
{
|
||||||
# tiles (one per each zoom level), *and* all "just outside the border"
|
# Location changed.
|
||||||
# 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.
|
|
||||||
|
|
||||||
$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];
|
Db::execute("
|
||||||
$z21y = $row[2];
|
delete from okapi_tile_caches
|
||||||
$ex = $z21x >> 8; # initially, z21x / <tile width>
|
where cache_id = '".mysql_real_escape_string($cache_id)."'
|
||||||
$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.
|
|
||||||
|
|
||||||
$tiles_in_this_region = array();
|
# Note, that after this operation, okapi_tile_status may be out-of-date.
|
||||||
for ($x=$ex-1; $x<=$ex+1; $x++)
|
# There might exist some rows with status==2, but they should be in status==1.
|
||||||
for ($y=$ey-1; $y<=$ey+1; $y++)
|
# Currently, we can ignore this, because status==1 is just a shortcut to
|
||||||
if (($x >= 0) && ($x < 1<<$zoom) && ($y >= 0) && ($y < 1<<$zoom))
|
# avoid making unnecessary queries.
|
||||||
$tiles_in_this_region[] = array($x, $y);
|
}
|
||||||
|
|
||||||
foreach ($tiles_in_this_region as $coords)
|
private static function add_geocache_to_cached_tiles(&$row)
|
||||||
{
|
{
|
||||||
list($x, $y) = $coords;
|
# 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;
|
$tiles_to_update = array();
|
||||||
$margin = 1 << ($scale - 3); # 32px of current $zoom level, measured in z21 pixels.
|
|
||||||
|
|
||||||
$left_z21x = ($x << $scale) - $margin;
|
# We will begin at zoom 21 and then go down to zoom 0.
|
||||||
$right_z21x = (($x + 1) << $scale) + $margin;
|
|
||||||
$top_z21y = ($y << $scale) - $margin;
|
|
||||||
$bottom_z21y = (($y + 1) << $scale) + $margin;
|
|
||||||
|
|
||||||
if ($z21x < $left_z21x)
|
$z21x = $row[1];
|
||||||
continue;
|
$z21y = $row[2];
|
||||||
if ($z21x > $right_z21x)
|
$ex = $z21x >> 8; # initially, z21x / <tile width>
|
||||||
continue;
|
$ey = $z21y >> 8; # initially, z21y / <tile height>
|
||||||
if ($z21y < $top_z21y)
|
for ($zoom = 21; $zoom >= 0; $zoom--, $ex >>= 1, $ey >>= 1)
|
||||||
continue;
|
{
|
||||||
if ($z21y > $bottom_z21y)
|
# ($ex, $ey) points to the "exact match" tile. We need to determine
|
||||||
continue;
|
# 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.
|
$scale = 8 + 21 - $zoom;
|
||||||
# Most of these tiles aren't cached at all. We need to update
|
$margin = 1 << ($scale - 3); # 32px of current $zoom level, measured in z21 pixels.
|
||||||
# only the cached ones.
|
|
||||||
|
|
||||||
$alternatives_escaped = array();
|
$left_z21x = ($x << $scale) - $margin;
|
||||||
foreach ($tiles_to_update as $coords)
|
$right_z21x = (($x + 1) << $scale) + $margin;
|
||||||
{
|
$top_z21y = ($y << $scale) - $margin;
|
||||||
list($z, $x, $y) = $coords;
|
$bottom_z21y = (($y + 1) << $scale) + $margin;
|
||||||
$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)
|
|
||||||
");
|
|
||||||
|
|
||||||
# We might have just filled some empty tiles (status 1) with data.
|
if ($z21x < $left_z21x)
|
||||||
# We need to update their status to 2.
|
continue;
|
||||||
|
if ($z21x > $right_z21x)
|
||||||
|
continue;
|
||||||
|
if ($z21y < $top_z21y)
|
||||||
|
continue;
|
||||||
|
if ($z21y > $bottom_z21y)
|
||||||
|
continue;
|
||||||
|
|
||||||
Db::execute("
|
# We found a match. Store it for later.
|
||||||
update okapi_tile_status
|
|
||||||
set status=2
|
|
||||||
where
|
|
||||||
(".implode(" or ", $alternatives_escaped).")
|
|
||||||
and status=1
|
|
||||||
");
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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)
|
# We have a list of all possible tiles that need updating.
|
||||||
{
|
# Most of these tiles aren't cached at all. We need to update
|
||||||
# Update all attributes (for all levels). Note, that we don't need to
|
# only the cached ones.
|
||||||
# update location ($row[1] and $row[2]) - this method is called ONLY
|
|
||||||
# when location stayed untouched!
|
|
||||||
|
|
||||||
Db::execute("
|
$alternatives_escaped = array();
|
||||||
update okapi_tile_caches
|
foreach ($tiles_to_update as $coords)
|
||||||
set
|
{
|
||||||
status = '".mysql_real_escape_string($row[3])."',
|
list($z, $x, $y) = $coords;
|
||||||
type = '".mysql_real_escape_string($row[4])."',
|
$alternatives_escaped[] = "(
|
||||||
rating = ".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").",
|
z = '".mysql_real_escape_string($z)."'
|
||||||
flags = '".mysql_real_escape_string($row[6])."'
|
and x = '".mysql_real_escape_string($x)."'
|
||||||
where
|
and y = '".mysql_real_escape_string($y)."'
|
||||||
cache_id = '".mysql_real_escape_string($row[0])."'
|
)";
|
||||||
");
|
}
|
||||||
}
|
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)
|
# We might have just filled some empty tiles (status 1) with data.
|
||||||
{
|
# We need to update their status to 2.
|
||||||
# Simply delete the cache at all zoom levels.
|
|
||||||
|
|
||||||
$cache_id = Db::select_value("
|
Db::execute("
|
||||||
select cache_id
|
update okapi_tile_status
|
||||||
from caches
|
set status=2
|
||||||
where wp_oc='".mysql_real_escape_string($c['object_key']['code'])."'
|
where
|
||||||
");
|
(".implode(" or ", $alternatives_escaped).")
|
||||||
self::remove_geocache_from_cached_tiles($cache_id);
|
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
|
class WebService
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Should be always true. You may temporarily set it to false, when you're
|
* Should be always true. You may temporarily set it to false, when you're
|
||||||
* testing/debugging the tile renderer.
|
* testing/debugging the tile renderer.
|
||||||
*/
|
*/
|
||||||
private static $USE_ETAGS_CACHE = true;
|
private static $USE_ETAGS_CACHE = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be always true. You may temporarily set it to false, when you're
|
* Should be always true. You may temporarily set it to false, when you're
|
||||||
* testing/debugging the tile renderer.
|
* testing/debugging the tile renderer.
|
||||||
*/
|
*/
|
||||||
private static $USE_IMAGE_CACHE = true;
|
private static $USE_IMAGE_CACHE = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be always true. You may temporarily set it to false, when you're
|
* 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.
|
* testing/debugging. Grep the code to check when this flag is used.
|
||||||
*/
|
*/
|
||||||
private static $USE_OTHER_CACHE = true;
|
private static $USE_OTHER_CACHE = true;
|
||||||
|
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 3
|
'min_auth_level' => 3
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function require_uint($request, $name, $min_value = 0)
|
private static function require_uint($request, $name, $min_value = 0)
|
||||||
{
|
{
|
||||||
$val = $request->get_parameter($name);
|
$val = $request->get_parameter($name);
|
||||||
if ($val === null)
|
if ($val === null)
|
||||||
throw new ParamMissing($name);
|
throw new ParamMissing($name);
|
||||||
$ret = intval($val);
|
$ret = intval($val);
|
||||||
if ($ret < 0 || ("$ret" !== $val))
|
if ($ret < 0 || ("$ret" !== $val))
|
||||||
throw new InvalidParam($name, "Expecting non-negative integer.");
|
throw new InvalidParam($name, "Expecting non-negative integer.");
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$checkpointA_started = microtime(true);
|
$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')))
|
if (!in_array($request->consumer->key, array('internal', 'facade')))
|
||||||
throw new BadRequest("Your Consumer Key has not been allowed to access this method.");
|
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');
|
$zoom = self::require_uint($request, 'z');
|
||||||
if ($zoom > 21)
|
if ($zoom > 21)
|
||||||
throw new InvalidParam('z', "Maximum value for this parameter is 21.");
|
throw new InvalidParam('z', "Maximum value for this parameter is 21.");
|
||||||
$x = self::require_uint($request, 'x');
|
$x = self::require_uint($request, 'x');
|
||||||
$y = self::require_uint($request, 'y');
|
$y = self::require_uint($request, 'y');
|
||||||
if ($x >= 1<<$zoom)
|
if ($x >= 1<<$zoom)
|
||||||
throw new InvalidParam('x', "Should be in 0..".((1<<$zoom) - 1).".");
|
throw new InvalidParam('x', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||||
if ($y >= 1<<$zoom)
|
if ($y >= 1<<$zoom)
|
||||||
throw new InvalidParam('y', "Should be in 0..".((1<<$zoom) - 1).".");
|
throw new InvalidParam('y', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||||
|
|
||||||
# Now, we will create a search set (or use one previously created).
|
# Now, we will create a search set (or use one previously created).
|
||||||
# Instead of creating a new OkapiInternalRequest object, we will pass
|
# Instead of creating a new OkapiInternalRequest object, we will pass
|
||||||
# the current request directly. We can do that, because we inherit all
|
# the current request directly. We can do that, because we inherit all
|
||||||
# of the "save" method's parameters.
|
# of the "save" method's parameters.
|
||||||
|
|
||||||
$search_set = OkapiServiceRunner::call('services/caches/search/save', $request);
|
$search_set = OkapiServiceRunner::call('services/caches/search/save', $request);
|
||||||
$set_id = $search_set['set_id'];
|
$set_id = $search_set['set_id'];
|
||||||
|
|
||||||
# Get caches which are present in the result set AND within the tile
|
# Get caches which are present in the result set AND within the tile
|
||||||
# (+ those around the borders).
|
# (+ those around the borders).
|
||||||
|
|
||||||
$rs = TileTree::query_fast($zoom, $x, $y, $set_id);
|
$rs = TileTree::query_fast($zoom, $x, $y, $set_id);
|
||||||
$rows = array();
|
$rows = array();
|
||||||
if ($rs !== null)
|
if ($rs !== null)
|
||||||
{
|
{
|
||||||
while ($row = mysql_fetch_row($rs))
|
while ($row = mysql_fetch_row($rs))
|
||||||
$rows[] = $row;
|
$rows[] = $row;
|
||||||
unset($row);
|
unset($row);
|
||||||
}
|
}
|
||||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointA", null,
|
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointA", null,
|
||||||
microtime(true) - $checkpointA_started);
|
microtime(true) - $checkpointA_started);
|
||||||
$checkpointB_started = microtime(true);
|
$checkpointB_started = microtime(true);
|
||||||
|
|
||||||
# Add dynamic, user-related flags.
|
# Add dynamic, user-related flags.
|
||||||
|
|
||||||
if (count($rows) > 0)
|
if (count($rows) > 0)
|
||||||
{
|
{
|
||||||
# Load user-related cache ids.
|
# Load user-related cache ids.
|
||||||
|
|
||||||
$cache_key = "tileuser/".$request->token->user_id;
|
$cache_key = "tileuser/".$request->token->user_id;
|
||||||
$user = self::$USE_OTHER_CACHE ? Cache::get($cache_key) : null;
|
$user = self::$USE_OTHER_CACHE ? Cache::get($cache_key) : null;
|
||||||
if ($user === null)
|
if ($user === null)
|
||||||
{
|
{
|
||||||
$user = array();
|
$user = array();
|
||||||
|
|
||||||
# Ignored caches.
|
# Ignored caches.
|
||||||
|
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select cache_id
|
select cache_id
|
||||||
from cache_ignore
|
from cache_ignore
|
||||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||||
");
|
");
|
||||||
$user['ignored'] = array();
|
$user['ignored'] = array();
|
||||||
while (list($cache_id) = mysql_fetch_row($rs))
|
while (list($cache_id) = mysql_fetch_row($rs))
|
||||||
$user['ignored'][$cache_id] = true;
|
$user['ignored'][$cache_id] = true;
|
||||||
|
|
||||||
# Found caches.
|
# Found caches.
|
||||||
|
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select distinct cache_id
|
select distinct cache_id
|
||||||
from cache_logs
|
from cache_logs
|
||||||
where
|
where
|
||||||
user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||||
and type = 1
|
and type = 1
|
||||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||||
");
|
");
|
||||||
$user['found'] = array();
|
$user['found'] = array();
|
||||||
while (list($cache_id) = mysql_fetch_row($rs))
|
while (list($cache_id) = mysql_fetch_row($rs))
|
||||||
$user['found'][$cache_id] = true;
|
$user['found'][$cache_id] = true;
|
||||||
|
|
||||||
# Own caches.
|
# Own caches.
|
||||||
|
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select distinct cache_id
|
select distinct cache_id
|
||||||
from caches
|
from caches
|
||||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||||
");
|
");
|
||||||
$user['own'] = array();
|
$user['own'] = array();
|
||||||
while (list($cache_id) = mysql_fetch_row($rs))
|
while (list($cache_id) = mysql_fetch_row($rs))
|
||||||
$user['own'][$cache_id] = true;
|
$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)
|
foreach ($rows as &$row_ref)
|
||||||
{
|
{
|
||||||
# Add the "found" flag (to indicate that this cache needs
|
# Add the "found" flag (to indicate that this cache needs
|
||||||
# to be drawn as found) and the "own" flag (to indicate that
|
# to be drawn as found) and the "own" flag (to indicate that
|
||||||
# the current user is the owner).
|
# the current user is the owner).
|
||||||
|
|
||||||
if (isset($user['found'][$row_ref[0]]))
|
if (isset($user['found'][$row_ref[0]]))
|
||||||
$row_ref[6] |= TileTree::$FLAG_FOUND; # $row[6] is "flags"
|
$row_ref[6] |= TileTree::$FLAG_FOUND; # $row[6] is "flags"
|
||||||
if (isset($user['own'][$row_ref[0]]))
|
if (isset($user['own'][$row_ref[0]]))
|
||||||
$row_ref[6] |= TileTree::$FLAG_OWN; # $row[6] is "flags"
|
$row_ref[6] |= TileTree::$FLAG_OWN; # $row[6] is "flags"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Compute the image hash/fingerprint. This will be used both for ETags
|
# Compute the image hash/fingerprint. This will be used both for ETags
|
||||||
# and internal cache ($cache_key).
|
# and internal cache ($cache_key).
|
||||||
|
|
||||||
$tile = new DefaultTileRenderer($zoom, $rows);
|
$tile = new DefaultTileRenderer($zoom, $rows);
|
||||||
$image_fingerprint = $tile->get_unique_hash();
|
$image_fingerprint = $tile->get_unique_hash();
|
||||||
|
|
||||||
# Start creating response.
|
# Start creating response.
|
||||||
|
|
||||||
$response = new OkapiHttpResponse();
|
$response = new OkapiHttpResponse();
|
||||||
$response->content_type = $tile->get_content_type();
|
$response->content_type = $tile->get_content_type();
|
||||||
$response->cache_control = "Cache-Control: private, max-age=600";
|
$response->cache_control = "Cache-Control: private, max-age=600";
|
||||||
$response->etag = 'W/"'.$image_fingerprint.'"';
|
$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,
|
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointB", null,
|
||||||
microtime(true) - $checkpointB_started);
|
microtime(true) - $checkpointB_started);
|
||||||
$checkpointC_started = microtime(true);
|
$checkpointC_started = microtime(true);
|
||||||
if (self::$USE_ETAGS_CACHE && ($request->etag == $response->etag))
|
if (self::$USE_ETAGS_CACHE && ($request->etag == $response->etag))
|
||||||
{
|
{
|
||||||
# Hit. Report the content was unmodified.
|
# Hit. Report the content was unmodified.
|
||||||
|
|
||||||
$response->etag = null;
|
$response->etag = null;
|
||||||
$response->status = "304 Not Modified";
|
$response->status = "304 Not Modified";
|
||||||
return $response;
|
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;
|
$cache_key = "tile/".$image_fingerprint;
|
||||||
$response->body = self::$USE_IMAGE_CACHE ? Cache::get($cache_key) : null;
|
$response->body = self::$USE_IMAGE_CACHE ? Cache::get($cache_key) : null;
|
||||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointC", null,
|
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointC", null,
|
||||||
microtime(true) - $checkpointC_started);
|
microtime(true) - $checkpointC_started);
|
||||||
$checkpointD_started = microtime(true);
|
$checkpointD_started = microtime(true);
|
||||||
if ($response->body !== null)
|
if ($response->body !== null)
|
||||||
{
|
{
|
||||||
# Hit. We will use the cached version of the image.
|
# 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();
|
$response->body = $tile->render();
|
||||||
Cache::set_scored($cache_key, $response->body);
|
Cache::set_scored($cache_key, $response->body);
|
||||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointD", null,
|
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointD", null,
|
||||||
microtime(true) - $checkpointD_started);
|
microtime(true) - $checkpointD_started);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get cache map tile</brief>
|
<brief>Get cache map tile</brief>
|
||||||
<issue-id>150</issue-id>
|
<issue-id>150</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p><b>CLOSED BETA</b> version. Due to long-term performance tests, currently
|
<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
|
this method is not publicly accessible. Let us know if you're interested
|
||||||
in using it.</p>
|
in using it.</p>
|
||||||
<p>Use this method to retrieve a tile-map of all caches included in your search
|
<p>Use this method to retrieve a tile-map of all caches included in your search
|
||||||
result.</p>
|
result.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='z'>Zoom level (0..21).</req>
|
<req name='z'>Zoom level (0..21).</req>
|
||||||
<req name='x'>Tile number on the X axis.</req>
|
<req name='x'>Tile number on the X axis.</req>
|
||||||
<req name='y'>Tile number on the Y axis.</req>
|
<req name='y'>Tile number on the Y axis.</req>
|
||||||
<import-params method="services/caches/search/save"/>
|
<import-params method="services/caches/search/save"/>
|
||||||
<returns>
|
<returns>
|
||||||
The PNG image with the requested map tile.
|
The PNG image with the requested map tile.
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -21,274 +21,283 @@ use okapi\OkapiLock;
|
|||||||
|
|
||||||
class TileTree
|
class TileTree
|
||||||
{
|
{
|
||||||
# Static flags (stored in the database).
|
# Static flags (stored in the database).
|
||||||
public static $FLAG_STAR = 0x01;
|
public static $FLAG_STAR = 0x01;
|
||||||
public static $FLAG_HAS_TRACKABLES = 0x02;
|
public static $FLAG_HAS_TRACKABLES = 0x02;
|
||||||
public static $FLAG_NOT_YET_FOUND = 0x04;
|
public static $FLAG_NOT_YET_FOUND = 0x04;
|
||||||
|
|
||||||
# Dynamic flags (added at runtime).
|
# Dynamic flags (added at runtime).
|
||||||
public static $FLAG_FOUND = 0x0100;
|
public static $FLAG_FOUND = 0x0100;
|
||||||
public static $FLAG_OWN = 0x0200;
|
public static $FLAG_OWN = 0x0200;
|
||||||
public static $FLAG_NEW = 0x0400;
|
public static $FLAG_NEW = 0x0400;
|
||||||
public static $FLAG_DRAW_CAPTION = 0x0800;
|
public static $FLAG_DRAW_CAPTION = 0x0800;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return null if not computed, 1 if computed and empty, 2 if computed and not empty.
|
* 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)
|
public static function get_tile_status($zoom, $x, $y)
|
||||||
{
|
{
|
||||||
return Db::select_value("
|
return Db::select_value("
|
||||||
select status
|
select status
|
||||||
from okapi_tile_status
|
from okapi_tile_status
|
||||||
where
|
where
|
||||||
z = '".mysql_real_escape_string($zoom)."'
|
z = '".mysql_real_escape_string($zoom)."'
|
||||||
and x = '".mysql_real_escape_string($x)."'
|
and x = '".mysql_real_escape_string($x)."'
|
||||||
and y = '".mysql_real_escape_string($y)."'
|
and y = '".mysql_real_escape_string($y)."'
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return MySQL's result set iterator over all caches which are present
|
* Return MySQL's result set iterator over all caches which are present
|
||||||
* in the given result set AND in the given tile.
|
* in the given result set AND in the given tile.
|
||||||
*
|
*
|
||||||
* Each row is an array of the following format:
|
* Each row is an array of the following format:
|
||||||
* list(cache_id, $pixel_x, $pixel_y, status, type, rating, flags, count).
|
* 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).
|
* 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
|
* Count is the number of other caches "eclipsed" by this geocache (such
|
||||||
* eclipsed geocaches are not included in the result).
|
* eclipsed geocaches are not included in the result).
|
||||||
*/
|
*/
|
||||||
public static function query_fast($zoom, $x, $y, $set_id)
|
public static function query_fast($zoom, $x, $y, $set_id)
|
||||||
{
|
{
|
||||||
# First, we check if the cache-set for this tile was already computed
|
# First, we check if the cache-set for this tile was already computed
|
||||||
# (and if it was, was it empty).
|
# (and if it was, was it empty).
|
||||||
|
|
||||||
$status = self::get_tile_status($zoom, $x, $y);
|
$status = self::get_tile_status($zoom, $x, $y);
|
||||||
if ($status === null) # Not yet computed.
|
if ($status === null) # Not yet computed.
|
||||||
{
|
{
|
||||||
# Note, that computing the tile does not involve taking any
|
# Note, that computing the tile does not involve taking any
|
||||||
# search parameters.
|
# search parameters.
|
||||||
|
|
||||||
$status = self::compute_tile($zoom, $x, $y);
|
$status = self::compute_tile($zoom, $x, $y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($status === 1) # Computed and empty.
|
if ($status === 1) # Computed and empty.
|
||||||
{
|
{
|
||||||
# This tile was already computed and it is empty.
|
# This tile was already computed and it is empty.
|
||||||
return null;
|
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_upper_x = $x << 8;
|
||||||
$tile_leftmost_y = $y << 8;
|
$tile_leftmost_y = $y << 8;
|
||||||
|
|
||||||
$zoom_escaped = "'".mysql_real_escape_string($zoom)."'";
|
$zoom_escaped = "'".mysql_real_escape_string($zoom)."'";
|
||||||
$tile_upper_x_escaped = "'".mysql_real_escape_string($tile_upper_x)."'";
|
$tile_upper_x_escaped = "'".mysql_real_escape_string($tile_upper_x)."'";
|
||||||
$tile_leftmost_y_escaped = "'".mysql_real_escape_string($tile_leftmost_y)."'";
|
$tile_leftmost_y_escaped = "'".mysql_real_escape_string($tile_leftmost_y)."'";
|
||||||
return Db::query("
|
return Db::query("
|
||||||
select
|
select
|
||||||
otc.cache_id,
|
otc.cache_id,
|
||||||
cast(otc.z21x >> (21 - $zoom_escaped) as signed) - $tile_upper_x_escaped as px,
|
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,
|
cast(otc.z21y >> (21 - $zoom_escaped) as signed) - $tile_leftmost_y_escaped as py,
|
||||||
otc.status, otc.type, otc.rating, otc.flags, count(*)
|
otc.status, otc.type, otc.rating, otc.flags, count(*)
|
||||||
from
|
from
|
||||||
okapi_tile_caches otc,
|
okapi_tile_caches otc,
|
||||||
okapi_search_results osr
|
okapi_search_results osr
|
||||||
where
|
where
|
||||||
z = $zoom_escaped
|
z = $zoom_escaped
|
||||||
and x = '".mysql_real_escape_string($x)."'
|
and x = '".mysql_real_escape_string($x)."'
|
||||||
and y = '".mysql_real_escape_string($y)."'
|
and y = '".mysql_real_escape_string($y)."'
|
||||||
and otc.cache_id = osr.cache_id
|
and otc.cache_id = osr.cache_id
|
||||||
and osr.set_id = '".mysql_real_escape_string($set_id)."'
|
and osr.set_id = '".mysql_real_escape_string($set_id)."'
|
||||||
group by
|
group by
|
||||||
z21x >> (3 + (21 - $zoom_escaped)),
|
z21x >> (3 + (21 - $zoom_escaped)),
|
||||||
z21y >> (3 + (21 - $zoom_escaped))
|
z21y >> (3 + (21 - $zoom_escaped))
|
||||||
order by
|
order by
|
||||||
z21y >> (3 + (21 - $zoom_escaped)),
|
z21y >> (3 + (21 - $zoom_escaped)),
|
||||||
z21x >> (3 + (21 - $zoom_escaped))
|
z21x >> (3 + (21 - $zoom_escaped))
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Precache the ($zoom, $x, $y) slot in the okapi_tile_caches table.
|
* Precache the ($zoom, $x, $y) slot in the okapi_tile_caches table.
|
||||||
*/
|
*/
|
||||||
public static function compute_tile($zoom, $x, $y)
|
public static function compute_tile($zoom, $x, $y)
|
||||||
{
|
{
|
||||||
$time_started = microtime(true);
|
$time_started = microtime(true);
|
||||||
|
|
||||||
# Note, that multiple threads may try to compute tiles simulatanously.
|
# Note, that multiple threads may try to compute tiles simulatanously.
|
||||||
# For low-level tiles, this can be expensive. WRTODO: Think of some
|
# For low-level tiles, this can be expensive. WRTODO: Think of some
|
||||||
# appropriate locks.
|
# appropriate locks.
|
||||||
|
|
||||||
$status = self::get_tile_status($zoom, $x, $y);
|
$status = self::get_tile_status($zoom, $x, $y);
|
||||||
if ($status !== null)
|
if ($status !== null)
|
||||||
return $status;
|
return $status;
|
||||||
|
|
||||||
if ($zoom === 0)
|
if ($zoom === 0)
|
||||||
{
|
{
|
||||||
# When computing zoom zero, we don't have a parent to speed up
|
# When computing zoom zero, we don't have a parent to speed up
|
||||||
# the computation. We need to use the caches table. Note, that
|
# the computation. We need to use the caches table. Note, that
|
||||||
# zoom level 0 contains *entire world*, so we don't have to use
|
# zoom level 0 contains *entire world*, so we don't have to use
|
||||||
# any WHERE condition in the following query.
|
# any WHERE condition in the following query.
|
||||||
|
|
||||||
# This can be done a little faster (without the use of internal requests),
|
# 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.
|
# but there is *no need* to - this query is run seldom and is cached.
|
||||||
|
|
||||||
$params = array();
|
$params = array();
|
||||||
$params['status'] = "Available|Temporarily unavailable|Archived"; # we want them all
|
$params['status'] = "Available|Temporarily unavailable|Archived"; # we want them all
|
||||||
$params['limit'] = "10000000"; # no limit
|
$params['limit'] = "10000000"; # no limit
|
||||||
|
|
||||||
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, $params);
|
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, $params);
|
||||||
$internal_request->skip_limits = true;
|
$internal_request->skip_limits = true;
|
||||||
$response = OkapiServiceRunner::call("services/caches/search/all", $internal_request);
|
$response = OkapiServiceRunner::call("services/caches/search/all", $internal_request);
|
||||||
$cache_codes = $response['results'];
|
$cache_codes = $response['results'];
|
||||||
|
|
||||||
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
||||||
'cache_codes' => implode('|', $cache_codes),
|
'cache_codes' => implode('|', $cache_codes),
|
||||||
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
||||||
));
|
));
|
||||||
$internal_request->skip_limits = true;
|
$internal_request->skip_limits = true;
|
||||||
$caches = OkapiServiceRunner::call("services/caches/geocaches", $internal_request);
|
$caches = OkapiServiceRunner::call("services/caches/geocaches", $internal_request);
|
||||||
|
|
||||||
foreach ($caches as $cache)
|
foreach ($caches as $cache)
|
||||||
{
|
{
|
||||||
$row = self::generate_short_row($cache);
|
$row = self::generate_short_row($cache);
|
||||||
Db::execute("
|
if (!$row) {
|
||||||
replace into okapi_tile_caches (
|
/* Some caches cannot be included, e.g. the ones near the poles. */
|
||||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
continue;
|
||||||
) values (
|
}
|
||||||
0, 0, 0,
|
Db::execute("
|
||||||
'".mysql_real_escape_string($row[0])."',
|
replace into okapi_tile_caches (
|
||||||
'".mysql_real_escape_string($row[1])."',
|
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||||
'".mysql_real_escape_string($row[2])."',
|
) values (
|
||||||
'".mysql_real_escape_string($row[3])."',
|
0, 0, 0,
|
||||||
'".mysql_real_escape_string($row[4])."',
|
'".mysql_real_escape_string($row[0])."',
|
||||||
".(($row[5] === null) ? "null" : "'".mysql_real_escape_string($row[5])."'").",
|
'".mysql_real_escape_string($row[1])."',
|
||||||
'".mysql_real_escape_string($row[6])."'
|
'".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])."'").",
|
||||||
$status = 2;
|
'".mysql_real_escape_string($row[6])."'
|
||||||
}
|
);
|
||||||
else
|
");
|
||||||
{
|
}
|
||||||
# We will use the parent tile to compute the contents of this tile.
|
$status = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# We will use the parent tile to compute the contents of this tile.
|
||||||
|
|
||||||
$parent_zoom = $zoom - 1;
|
$parent_zoom = $zoom - 1;
|
||||||
$parent_x = $x >> 1;
|
$parent_x = $x >> 1;
|
||||||
$parent_y = $y >> 1;
|
$parent_y = $y >> 1;
|
||||||
|
|
||||||
$status = self::get_tile_status($parent_zoom, $parent_x, $parent_y);
|
$status = self::get_tile_status($parent_zoom, $parent_x, $parent_y);
|
||||||
if ($status === null) # Not computed.
|
if ($status === null) # Not computed.
|
||||||
{
|
{
|
||||||
$time_started = microtime(true);
|
$time_started = microtime(true);
|
||||||
$status = self::compute_tile($parent_zoom, $parent_x, $parent_y);
|
$status = self::compute_tile($parent_zoom, $parent_x, $parent_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($status === 1) # Computed and empty.
|
if ($status === 1) # Computed and empty.
|
||||||
{
|
{
|
||||||
# No need to check.
|
# No need to check.
|
||||||
}
|
}
|
||||||
else # Computed, not empty.
|
else # Computed, not empty.
|
||||||
{
|
{
|
||||||
$scale = 8 + 21 - $zoom;
|
$scale = 8 + 21 - $zoom;
|
||||||
$parentcenter_z21x = (($parent_x << 1) | 1) << $scale;
|
$parentcenter_z21x = (($parent_x << 1) | 1) << $scale;
|
||||||
$parentcenter_z21y = (($parent_y << 1) | 1) << $scale;
|
$parentcenter_z21y = (($parent_y << 1) | 1) << $scale;
|
||||||
$margin = 1 << ($scale - 2);
|
$margin = 1 << ($scale - 2);
|
||||||
$left_z21x = (($parent_x << 1) << $scale) - $margin;
|
$left_z21x = (($parent_x << 1) << $scale) - $margin;
|
||||||
$right_z21x = ((($parent_x + 1) << 1) << $scale) + $margin;
|
$right_z21x = ((($parent_x + 1) << 1) << $scale) + $margin;
|
||||||
$top_z21y = (($parent_y << 1) << $scale) - $margin;
|
$top_z21y = (($parent_y << 1) << $scale) - $margin;
|
||||||
$bottom_z21y = ((($parent_y + 1) << 1) << $scale) + $margin;
|
$bottom_z21y = ((($parent_y + 1) << 1) << $scale) + $margin;
|
||||||
|
|
||||||
# Choose the right quarter.
|
# Choose the right quarter.
|
||||||
# |1 2|
|
# |1 2|
|
||||||
# |3 4|
|
# |3 4|
|
||||||
|
|
||||||
if ($x & 1) # 2 or 4
|
if ($x & 1) # 2 or 4
|
||||||
$left_z21x = $parentcenter_z21x - $margin;
|
$left_z21x = $parentcenter_z21x - $margin;
|
||||||
else # 1 or 3
|
else # 1 or 3
|
||||||
$right_z21x = $parentcenter_z21x + $margin;
|
$right_z21x = $parentcenter_z21x + $margin;
|
||||||
if ($y & 1) # 3 or 4
|
if ($y & 1) # 3 or 4
|
||||||
$top_z21y = $parentcenter_z21y - $margin;
|
$top_z21y = $parentcenter_z21y - $margin;
|
||||||
else # 1 or 2
|
else # 1 or 2
|
||||||
$bottom_z21y = $parentcenter_z21y + $margin;
|
$bottom_z21y = $parentcenter_z21y + $margin;
|
||||||
|
|
||||||
# Cache the result.
|
# Cache the result.
|
||||||
|
|
||||||
Db::execute("
|
Db::execute("
|
||||||
replace into okapi_tile_caches (
|
replace into okapi_tile_caches (
|
||||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||||
)
|
)
|
||||||
select
|
select
|
||||||
'".mysql_real_escape_string($zoom)."',
|
'".mysql_real_escape_string($zoom)."',
|
||||||
'".mysql_real_escape_string($x)."',
|
'".mysql_real_escape_string($x)."',
|
||||||
'".mysql_real_escape_string($y)."',
|
'".mysql_real_escape_string($y)."',
|
||||||
cache_id, z21x, z21y, status, type, rating, flags
|
cache_id, z21x, z21y, status, type, rating, flags
|
||||||
from okapi_tile_caches
|
from okapi_tile_caches
|
||||||
where
|
where
|
||||||
z = '".mysql_real_escape_string($parent_zoom)."'
|
z = '".mysql_real_escape_string($parent_zoom)."'
|
||||||
and x = '".mysql_real_escape_string($parent_x)."'
|
and x = '".mysql_real_escape_string($parent_x)."'
|
||||||
and y = '".mysql_real_escape_string($parent_y)."'
|
and y = '".mysql_real_escape_string($parent_y)."'
|
||||||
and z21x between $left_z21x and $right_z21x
|
and z21x between $left_z21x and $right_z21x
|
||||||
and z21y between $top_z21y and $bottom_z21y
|
and z21y between $top_z21y and $bottom_z21y
|
||||||
");
|
");
|
||||||
$test = Db::select_value("
|
$test = Db::select_value("
|
||||||
select 1
|
select 1
|
||||||
from okapi_tile_caches
|
from okapi_tile_caches
|
||||||
where
|
where
|
||||||
z = '".mysql_real_escape_string($zoom)."'
|
z = '".mysql_real_escape_string($zoom)."'
|
||||||
and x = '".mysql_real_escape_string($x)."'
|
and x = '".mysql_real_escape_string($x)."'
|
||||||
and y = '".mysql_real_escape_string($y)."'
|
and y = '".mysql_real_escape_string($y)."'
|
||||||
limit 1;
|
limit 1;
|
||||||
");
|
");
|
||||||
if ($test)
|
if ($test)
|
||||||
$status = 2;
|
$status = 2;
|
||||||
else
|
else
|
||||||
$status = 1;
|
$status = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Mark tile as computed.
|
# Mark tile as computed.
|
||||||
|
|
||||||
Db::execute("
|
Db::execute("
|
||||||
replace into okapi_tile_status (z, x, y, status)
|
replace into okapi_tile_status (z, x, y, status)
|
||||||
values (
|
values (
|
||||||
'".mysql_real_escape_string($zoom)."',
|
'".mysql_real_escape_string($zoom)."',
|
||||||
'".mysql_real_escape_string($x)."',
|
'".mysql_real_escape_string($x)."',
|
||||||
'".mysql_real_escape_string($y)."',
|
'".mysql_real_escape_string($y)."',
|
||||||
'".mysql_real_escape_string($status)."'
|
'".mysql_real_escape_string($status)."'
|
||||||
);
|
);
|
||||||
");
|
");
|
||||||
|
|
||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert OKAPI's cache object to a short database row to be inserted
|
* 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:
|
* into okapi_tile_caches table. Returns the list of the following attributes:
|
||||||
* cache_id, z21x, z21y, status, type, rating, flags (rating might be null!).
|
* cache_id, z21x, z21y, status, type, rating, flags (rating might be null!).
|
||||||
*/
|
*/
|
||||||
public static function generate_short_row($cache)
|
public static function generate_short_row($cache)
|
||||||
{
|
{
|
||||||
list($lat, $lon) = explode("|", $cache['location']);
|
list($lat, $lon) = explode("|", $cache['location']);
|
||||||
list($z21x, $z21y) = self::latlon_to_z21xy($lat, $lon);
|
try {
|
||||||
$flags = 0;
|
list($z21x, $z21y) = self::latlon_to_z21xy($lat, $lon);
|
||||||
if (($cache['founds'] > 6) && (($cache['recommendations'] / $cache['founds']) > 0.3))
|
} catch (Exception $e) {
|
||||||
$flags |= self::$FLAG_STAR;
|
/* E.g. division by zero, if the cache is placed at the north pole. */
|
||||||
if ($cache['trackables_count'] > 0)
|
return false;
|
||||||
$flags |= self::$FLAG_HAS_TRACKABLES;
|
}
|
||||||
if ($cache['founds'] == 0)
|
$flags = 0;
|
||||||
$flags |= self::$FLAG_NOT_YET_FOUND;
|
if (($cache['founds'] > 6) && (($cache['recommendations'] / $cache['founds']) > 0.3))
|
||||||
return array($cache['internal_id'], $z21x, $z21y, Okapi::cache_status_name2id($cache['status']),
|
$flags |= self::$FLAG_STAR;
|
||||||
Okapi::cache_type_name2id($cache['type']), $cache['rating'], $flags);
|
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)
|
private static function latlon_to_z21xy($lat, $lon)
|
||||||
{
|
{
|
||||||
$offset = 128 << 21;
|
$offset = 128 << 21;
|
||||||
$x = round($offset + ($offset * $lon / 180));
|
$x = round($offset + ($offset * $lon / 180));
|
||||||
$y = round($offset - $offset/pi() * log((1 + sin($lat * pi() / 180)) / (1 - sin($lat * pi() / 180))) / 2);
|
$y = round($offset - $offset/pi() * log((1 + sin($lat * pi() / 180)) / (1 - sin($lat * pi() / 180))) / 2);
|
||||||
return array($x, $y);
|
return array($x, $y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,74 +17,74 @@ use okapi\Settings;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 3
|
'min_auth_level' => 3
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# User is already verified (via OAuth), but we need to verify the
|
# 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
|
# 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.
|
# on it - this will also throw a proper exception if it doesn't exist.
|
||||||
|
|
||||||
$cache_code = $request->get_parameter('cache_code');
|
$cache_code = $request->get_parameter('cache_code');
|
||||||
if ($cache_code == null)
|
if ($cache_code == null)
|
||||||
throw new ParamMissing('cache_code');
|
throw new ParamMissing('cache_code');
|
||||||
$geocache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
$geocache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
$request->consumer, $request->token, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
||||||
|
|
||||||
# watched
|
# watched
|
||||||
|
|
||||||
if ($tmp = $request->get_parameter('watched'))
|
if ($tmp = $request->get_parameter('watched'))
|
||||||
{
|
{
|
||||||
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
||||||
throw new InvalidParam('watched', $tmp);
|
throw new InvalidParam('watched', $tmp);
|
||||||
if ($tmp == 'true')
|
if ($tmp == 'true')
|
||||||
Db::execute("
|
Db::execute("
|
||||||
insert ignore into cache_watches (cache_id, user_id)
|
insert ignore into cache_watches (cache_id, user_id)
|
||||||
values (
|
values (
|
||||||
'".mysql_real_escape_string($geocache['internal_id'])."',
|
'".mysql_real_escape_string($geocache['internal_id'])."',
|
||||||
'".mysql_real_escape_string($request->token->user_id)."'
|
'".mysql_real_escape_string($request->token->user_id)."'
|
||||||
);
|
);
|
||||||
");
|
");
|
||||||
elseif ($tmp == 'false')
|
elseif ($tmp == 'false')
|
||||||
Db::execute("
|
Db::execute("
|
||||||
delete from cache_watches
|
delete from cache_watches
|
||||||
where
|
where
|
||||||
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
||||||
and user_id = '".mysql_real_escape_string($request->token->user_id)."';
|
and user_id = '".mysql_real_escape_string($request->token->user_id)."';
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
# ignored
|
# ignored
|
||||||
|
|
||||||
if ($tmp = $request->get_parameter('ignored'))
|
if ($tmp = $request->get_parameter('ignored'))
|
||||||
{
|
{
|
||||||
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
||||||
throw new InvalidParam('ignored', $tmp);
|
throw new InvalidParam('ignored', $tmp);
|
||||||
if ($tmp == 'true')
|
if ($tmp == 'true')
|
||||||
Db::execute("
|
Db::execute("
|
||||||
insert ignore into cache_ignore (cache_id, user_id)
|
insert ignore into cache_ignore (cache_id, user_id)
|
||||||
values (
|
values (
|
||||||
'".mysql_real_escape_string($geocache['internal_id'])."',
|
'".mysql_real_escape_string($geocache['internal_id'])."',
|
||||||
'".mysql_real_escape_string($request->token->user_id)."'
|
'".mysql_real_escape_string($request->token->user_id)."'
|
||||||
);
|
);
|
||||||
");
|
");
|
||||||
elseif ($tmp == 'false')
|
elseif ($tmp == 'false')
|
||||||
Db::execute("
|
Db::execute("
|
||||||
delete from cache_ignore
|
delete from cache_ignore
|
||||||
where
|
where
|
||||||
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
||||||
and user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
and user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = array(
|
$result = array(
|
||||||
'success' => true,
|
'success' => true,
|
||||||
);
|
);
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Mark cache as watched or ignored</brief>
|
<brief>Mark cache as watched or ignored</brief>
|
||||||
<issue-id>166</issue-id>
|
<issue-id>166</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method allows your users to mark the geocache as <b>watched</b> or
|
<p>This method allows your users to mark the geocache as <b>watched</b> or
|
||||||
<b>ignored</b>.
|
<b>ignored</b>.
|
||||||
Read the docs on separate parameters for details.</p>
|
Read the docs on separate parameters for details.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='cache_code'>
|
<req name='cache_code'>
|
||||||
<p>Code of the geocache.</p>
|
<p>Code of the geocache.</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='watched' default='unchanged'>
|
<opt name='watched' default='unchanged'>
|
||||||
<p>Mark (or unmark) the cache as watched. This should be <b>true</b>,
|
<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
|
<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>
|
flag with the <b>is_watched</b> field of the geocache method.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='ignored' default='unchanged'>
|
<opt name='ignored' default='unchanged'>
|
||||||
<p>Mark (or unmark) the cache as ignored. This should be <b>true</b>,
|
<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
|
<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>
|
flag with the <b>is_ignored</b> field of the geocache method.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>success</b> - true, if all went well.</li>
|
<li><b>success</b> - true, if all went well.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Please note, that currently this will <b>always</b> be true! Nothing can go
|
<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,
|
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,
|
you will get an HTTP 400 response). If you have received an HTTP 200 response,
|
||||||
then you may assume that all went well.</p>
|
then you may assume that all went well.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -20,17 +20,18 @@ require_once('searching.inc.php');
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$search_params = SearchAssistant::get_common_search_params($request);
|
$search_assistant = new SearchAssistant($request);
|
||||||
$result = SearchAssistant::get_common_search_result($search_params);
|
$search_assistant->prepare_common_search_params();
|
||||||
return Okapi::formatted_response($request, $result);
|
$result = $search_assistant->get_common_search_result();
|
||||||
}
|
return Okapi::formatted_response($request, $result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,209 +1,209 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Search for geocaches</brief>
|
<brief>Search for geocaches</brief>
|
||||||
<issue-id>15</issue-id>
|
<issue-id>15</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Search for geocaches using some simple filters.
|
<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>
|
All of them are optional, but you surely want to use at least some of them.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>If you're looking for a way to keep your geocaching database in sync with ours,
|
<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>
|
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.
|
<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>
|
This way, you can get much more data in <b>one request</b>.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</desc>
|
</desc>
|
||||||
<opt name='type'>
|
<opt name='type'>
|
||||||
<p>Pipe-separated list of cache type codes. If given, the results will be limited
|
<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
|
to the given cache types. For a list of cache type codes, see services/caches/geocache
|
||||||
method.</p>
|
method.</p>
|
||||||
<p><b>Notice:</b> If you want to include all cache types <b>except</b>
|
<p><b>Notice:</b> If you want to include all cache types <b>except</b>
|
||||||
given ones, prepend your list with the "-" sign.</p>
|
given ones, prepend your list with the "-" sign.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='status' default='Available'>
|
<opt name='status' default='Available'>
|
||||||
<p>Pipe-separated list of status codes. Only caches matching any of the given
|
<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
|
statuses will included in the response. For a list of cache status codes, see
|
||||||
services/caches/geocache method.</p>
|
services/caches/geocache method.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='owner_uuid'>
|
<opt name='owner_uuid'>
|
||||||
<p>Pipe-separated list of user IDs. If given, the list of returned caches
|
<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>
|
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> 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
|
<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>
|
owned by the given users, prepend your list with the "-" sign.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='name'>
|
<opt name='name'>
|
||||||
<p>UTF-8 encoded string - the name (or part of the name) of the cache.</p>
|
<p>UTF-8 encoded string - the name (or part of the name) of the cache.</p>
|
||||||
<p>Allowed wildcard characters:</p>
|
<p>Allowed wildcard characters:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>asterisk ("*") will match any string of characters,</li>
|
<li>asterisk ("*") will match any string of characters,</li>
|
||||||
<li>underscore ("_") will match any single character.</li>
|
<li>underscore ("_") will match any single character.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Name matching is case-insensitive. Maximum length for the <b>name</b> parameter
|
<p>Name matching is case-insensitive. Maximum length for the <b>name</b> parameter
|
||||||
is 100 characters.</p>
|
is 100 characters.</p>
|
||||||
<p><b>Examples:</b></p>
|
<p><b>Examples:</b></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>"name=the *" returns caches which name starts with "the " (or "The ", etc.),</li>
|
<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" 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=*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>
|
<li>"name=*tower_" will match "Water Towers" but will <b>not</b> match "Water Tower".</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p><b>Notice:</b> Cache code and name are two different things - if you want to
|
<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>
|
find a cache by its code, use the services/caches/geocache method.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='terrain' default='1-5'>
|
<opt name='terrain' default='1-5'>
|
||||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
<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>
|
Only caches with terrain rating between these numbers (inclusive) will be returned.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='difficulty' default='1-5'>
|
<opt name='difficulty' default='1-5'>
|
||||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
<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>
|
Only caches with difficulty rating between these numbers (inclusive) will be returned.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='size' class='deprecated'>
|
<opt name='size' class='deprecated'>
|
||||||
<p>Deprecated. Please use <b>size2</b> instead - this will allow you to
|
<p>Deprecated. Please use <b>size2</b> instead - this will allow you to
|
||||||
differentiate "nano" vs. "micro" and "none" vs. "other" sizes
|
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>
|
(<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.
|
<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
|
Only caches with size attribute between these numbers (inclusive) will be returned
|
||||||
(1 - micro, 5 - very big).</p>
|
(1 - micro, 5 - very big).</p>
|
||||||
<p><b>Notice:</b> If you use this parameter, all caches which do not have a container
|
<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
|
(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
|
with no container included, append "|X" suffix to the value of this parameter
|
||||||
(e.g. "3-5|X").</p>
|
(e.g. "3-5|X").</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='size2'>
|
<opt name='size2'>
|
||||||
<p>Pipe-separated list of "size2 codes". Only matching caches will be
|
<p>Pipe-separated list of "size2 codes". Only matching caches will be
|
||||||
included. The codes are: 'none', 'nano', 'micro', 'small', 'regular',
|
included. The codes are: 'none', 'nano', 'micro', 'small', 'regular',
|
||||||
'large', 'xlarge', 'other'.</p>
|
'large', 'xlarge', 'other'.</p>
|
||||||
<p><b>Note:</b> Not all OC servers use all of these. I.e. OCPL does not
|
<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>
|
have 'nano' nor 'other' caches (but it might have them in the future).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='rating'>
|
<opt name='rating'>
|
||||||
<p>A string "X-Y", where X and Y are integers between 1 and 5, and X <= Y.
|
<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
|
Only caches with an overall rating between these numbers (inclusive) will be returned
|
||||||
(1 - poor, 5 - excellent).</p>
|
(1 - poor, 5 - excellent).</p>
|
||||||
<p><b>Notice:</b> If you use this parameter, all caches with too few votes will be
|
<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
|
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>
|
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.
|
<p><b>Notice:</b> Some OC installations do not provide ratings for their geocaches.
|
||||||
On such installation, this parameter will be ignored.</p>
|
On such installation, this parameter will be ignored.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='min_rcmds'>
|
<opt name='min_rcmds'>
|
||||||
<p>There are two possible value-types for this argument:</p>
|
<p>There are two possible value-types for this argument:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
<li>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
||||||
at least <i>N</i> recommendations.</li>
|
at least <i>N</i> recommendations.</li>
|
||||||
<li>Integer N with a percent sign appended (e.g. "20%"). The result will contain
|
<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.
|
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>
|
Please note, that this is useful only with conjunction with <b>min_founds</b>
|
||||||
parameter.</li>
|
parameter.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='min_founds'>
|
<opt name='min_founds'>
|
||||||
<p>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
<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>
|
been found at least <i>N</i> times. Useful if you want to skip "unverified" caches.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='max_founds'>
|
<opt name='max_founds'>
|
||||||
<p>Integer N. If <i>N</i> given, the result will contain only those caches which have
|
<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>
|
been found at most <i>N</i> times. Useful for FTF hunters.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='modified_since'>
|
<opt name='modified_since'>
|
||||||
<p>A date and time string. This should be in ISO 8601 format (currently any
|
<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>
|
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,
|
function also will do, but most of them don't handle time zones properly,
|
||||||
try to use ISO 8601!).</p>
|
try to use ISO 8601!).</p>
|
||||||
<p>If given, the list of returned geocaches will be limited to those which were
|
<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
|
created or modified since that date. (Note: currently caches do not get
|
||||||
"modified" when user makes a log entry.)</p>
|
"modified" when user makes a log entry.)</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='found_status' default='either'>
|
<opt name='found_status' default='either'>
|
||||||
<p><b>Notice:</b> This parameter may be used only for requests signed with an Access Token
|
<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>
|
(you will need to use <b>Level 3</b> Authentication).</p>
|
||||||
<p>Should be one of the following:</p>
|
<p>Should be one of the following:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>found_only</b> - only caches found by the user will be returned,</li>
|
<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>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>
|
<li><b>either</b> - all caches will be returned.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='found_by'>
|
<opt name='found_by'>
|
||||||
<p>User UUID. If given, the response will only include geocaches found by
|
<p>User UUID. If given, the response will only include geocaches found by
|
||||||
the given user.</p>
|
the given user.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='not_found_by'>
|
<opt name='not_found_by'>
|
||||||
<p>User UUID. If given, the response will only include geocaches not found by
|
<p>User UUID. If given, the response will only include geocaches not found by
|
||||||
the given user.</p>
|
the given user.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='watched_only' default='false'>
|
<opt name='watched_only' default='false'>
|
||||||
<p><b>Notice:</b> This parameter may be used only for requests signed with an Access Token
|
<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>
|
(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
|
<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
|
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>
|
of particular interest (e.g. "all the caches I plan to find today").</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='exclude_ignored' default='false'>
|
<opt name='exclude_ignored' default='false'>
|
||||||
<p><b>Notice:</b> This parameter may be used only for requests signed
|
<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>
|
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
|
<p>Boolean. If set to <b>true</b>, caches which the user has marked as ignored
|
||||||
will not be included in the result.</p>
|
will not be included in the result.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='exclude_my_own' default='false'>
|
<opt name='exclude_my_own' default='false'>
|
||||||
<p><b>Notice:</b> This parameter may be used only for requests signed
|
<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).
|
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>
|
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
|
<p>Boolean. If set to <b>true</b>, caches which the user is an owner of will
|
||||||
not be included in the result.</p>
|
not be included in the result.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='with_trackables_only' default='false'>
|
<opt name='with_trackables_only' default='false'>
|
||||||
Boolean. If set to <b>true</b>, only caches with at least one trackable
|
Boolean. If set to <b>true</b>, only caches with at least one trackable
|
||||||
will be included in the result.
|
will be included in the result.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='ftf_hunter' default='false'>
|
<opt name='ftf_hunter' default='false'>
|
||||||
Boolean. If set to <b>true</b>, only caches which have not yet been
|
Boolean. If set to <b>true</b>, only caches which have not yet been
|
||||||
found <b>by anyone</b> will be included.
|
found <b>by anyone</b> will be included.
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='set_and'>
|
<opt name='set_and'>
|
||||||
<p>ID of a set previously created with the <b>search/save</b> method.
|
<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
|
If given, the results are <a href='http://en.wikipedia.org/wiki/Logical_conjunction'>AND</a>ed
|
||||||
together with this set.</p>
|
together with this set.</p>
|
||||||
<p>If you want to list the set contents only, please note the default
|
<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
|
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>
|
in order to include unavailable and/or archived geocaches within the set.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='limit' default='100'>
|
<opt name='limit' default='100'>
|
||||||
<p>Integer in range 1..500. Maximum number of cache codes returned.</p>
|
<p>Integer in range 1..500. Maximum number of cache codes returned.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='offset' default='0'>
|
<opt name='offset' default='0'>
|
||||||
<p>An offset, the amount of items to skip at the beginning of the result. Combined with limit
|
<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
|
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.
|
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>
|
Have a peek at the <b>replicate</b> module if you need all the caches.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='order_by'>
|
<opt name='order_by'>
|
||||||
<p>Pipe separated list of fields to order the results by. Prefix the field name with
|
<p>Pipe separated list of fields to order the results by. Prefix the field name with
|
||||||
a '-' sign to indicate a descending order.</p>
|
a '-' sign to indicate a descending order.</p>
|
||||||
<p>Currently, fields which you can order by include: <b>code</b>, <b>name</b>,
|
<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>
|
<b>founds</b>, <b>rcmds</b>, <b>rcmds%</b> (tell us if you want more).</p>
|
||||||
<p><b>Examples:</b></p>
|
<p><b>Examples:</b></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>to order by cache name use "order_by=name" or "order_by=+name",</li>
|
<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>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>
|
<li>multicolumn sorting is also allowed, ex. "order_by=-founds|name"</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p><b>Note:</b> Try to avoid executing separate OKAPI request every time you
|
<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
|
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>
|
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>),
|
<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
|
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
|
custom <b>order_by</b> parameter, then we will try to order by your preference
|
||||||
first, and then by the distance later.</p>
|
first, and then by the distance later.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>results</b> - a list of cache codes,</li>
|
<li><b>results</b> - a list of cache codes,</li>
|
||||||
<li><b>more</b> - boolean, <b>true</b> means that there were more
|
<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
|
results for your query, but they were not returned because of the
|
||||||
<b>limit</b> parameter.</li>
|
<b>limit</b> parameter.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -12,76 +12,83 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# You may wonder, why there are no parameters like "bbox" or "center" in the
|
# 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.
|
# "search/all" method. This is *intentional* and should be kept this way.
|
||||||
# Such parameters would fall in conflict with each other and - in result -
|
# Such parameters would fall in conflict with each other and - in result -
|
||||||
# make the documentation very fuzzy. That's why they were intentionally
|
# make the documentation very fuzzy. That's why they were intentionally
|
||||||
# left out of the "search/all" method, and put in separate (individual) ones.
|
# left out of the "search/all" method, and put in separate (individual) ones.
|
||||||
# It's much easier to grasp their meaning this way.
|
# It's much easier to grasp their meaning this way.
|
||||||
|
|
||||||
$tmp = $request->get_parameter('bbox');
|
$tmp = $request->get_parameter('bbox');
|
||||||
if (!$tmp)
|
if (!$tmp)
|
||||||
throw new ParamMissing('bbox');
|
throw new ParamMissing('bbox');
|
||||||
$parts = explode('|', $tmp);
|
$parts = explode('|', $tmp);
|
||||||
if (count($parts) != 4)
|
if (count($parts) != 4)
|
||||||
throw new InvalidParam('bbox', "Expecting 4 pipe-separated parts, got ".count($parts).".");
|
throw new InvalidParam('bbox', "Expecting 4 pipe-separated parts, got ".count($parts).".");
|
||||||
foreach ($parts as &$part_ref)
|
foreach ($parts as &$part_ref)
|
||||||
{
|
{
|
||||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $part_ref))
|
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $part_ref))
|
||||||
throw new InvalidParam('bbox', "'$part_ref' is not a valid float number.");
|
throw new InvalidParam('bbox', "'$part_ref' is not a valid float number.");
|
||||||
$part_ref = floatval($part_ref);
|
$part_ref = floatval($part_ref);
|
||||||
}
|
}
|
||||||
list($bbsouth, $bbwest, $bbnorth, $bbeast) = $parts;
|
list($bbsouth, $bbwest, $bbnorth, $bbeast) = $parts;
|
||||||
if ($bbnorth <= $bbsouth)
|
if ($bbnorth <= $bbsouth)
|
||||||
throw new InvalidParam('bbox', "Northern edge must be situated to the north of the southern edge.");
|
throw new InvalidParam('bbox', "Northern edge must be situated to the north of the southern edge.");
|
||||||
if ($bbeast == $bbwest)
|
if ($bbeast == $bbwest)
|
||||||
throw new InvalidParam('bbox', "Eastern edge longitude is the same as the western one.");
|
throw new InvalidParam('bbox', "Eastern edge longitude is the same as the western one.");
|
||||||
if ($bbnorth > 90 || $bbnorth < -90 || $bbsouth > 90 || $bbsouth < -90)
|
if ($bbnorth > 90 || $bbnorth < -90 || $bbsouth > 90 || $bbsouth < -90)
|
||||||
throw new InvalidParam('bbox', "Latitudes have to be within -90..90 range.");
|
throw new InvalidParam('bbox', "Latitudes have to be within -90..90 range.");
|
||||||
if ($bbeast > 180 || $bbeast < -180 || $bbwest > 180 || $bbwest < -180)
|
if ($bbeast > 180 || $bbeast < -180 || $bbwest > 180 || $bbwest < -180)
|
||||||
throw new InvalidParam('bbox', "Longitudes have to be within -180..180 range.");
|
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();
|
$search_assistant = new SearchAssistant($request);
|
||||||
$where_conds[] = "caches.latitude between '".mysql_real_escape_string($bbsouth)."' and '".mysql_real_escape_string($bbnorth)."'";
|
$search_assistant->prepare_common_search_params();
|
||||||
if ($bbeast > $bbwest)
|
$search_assistant->prepare_location_search_params();
|
||||||
{
|
|
||||||
# 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)."')";
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
$where_conds = array();
|
||||||
# In the method description, we promised to return caches ordered by the *rough*
|
$where_conds[] = $search_assistant->get_latitude_expr()." between '".mysql_real_escape_string($bbsouth)."' and '".mysql_real_escape_string($bbnorth)."'";
|
||||||
# distance from the center of the bounding box. We'll use ORDER BY with a simplified
|
if ($bbeast > $bbwest)
|
||||||
# distance formula and combine it with the LIMIT clause to get the best results.
|
{
|
||||||
#
|
# 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);
|
$center_lat = ($bbsouth + $bbnorth) / 2.0;
|
||||||
$search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
|
$center_lon = ($bbwest + $bbeast) / 2.0;
|
||||||
$search_params['order_by'][] = Okapi::get_distance_sql($center_lat, $center_lon,
|
|
||||||
"caches.latitude", "caches.longitude"); # not replaced; added to the end!
|
|
||||||
|
|
||||||
$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>
|
<xml>
|
||||||
<brief>Search for caches within specified bounding box</brief>
|
<brief>Search for caches within specified bounding box</brief>
|
||||||
<issue-id>16</issue-id>
|
<issue-id>16</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method is similar to the search/all method, but the results
|
<p>This method is similar to the search/all method, but the results
|
||||||
are restricted to the caches situated within a given bounding box
|
are restricted to the caches situated within a given bounding box
|
||||||
(a rectangle on the map).</p>
|
(a rectangle on the map).</p>
|
||||||
<p>Unless overriden, results are ordered by the distance from the center of the bounding
|
<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
|
box. This means, that if you hit the limit of geocaches
|
||||||
returned, you will receive the ones that are in the middle of your
|
returned, you will receive the ones that are in the middle of your
|
||||||
box, and miss the ones on the edges.</p>
|
box, and miss the ones on the edges.</p>
|
||||||
<p>Usually you will want to use search_and_retrieve method instead of this one.
|
<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>
|
This way, you can get much more data in <b>one request</b>.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='bbox'>
|
<req name='bbox'>
|
||||||
<p>The bounding box within to search for caches. The box is defined
|
<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>
|
by a string in "<b>S|W|N|E</b>" format, where:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>S</b> stands for southern edge latitude of the box,</li>
|
<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>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>N</b> stands for northern edge latitude of the box,</li>
|
||||||
<li><b>E</b> stands for eastern edge longitude of the box.</li>
|
<li><b>E</b> stands for eastern edge longitude of the box.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Use positive numbers for latitudes in the northern hemisphere and
|
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||||
longitudes in the eastern hemisphere (and negative for southern and
|
longitudes in the eastern hemisphere (and negative for southern and
|
||||||
western hemispheres accordingly). These are full degrees with a dot
|
western hemispheres accordingly). These are full degrees with a dot
|
||||||
as a decimal point (ex. "48.7|15.8|54|24.9").</p>
|
as a decimal point (ex. "48.7|15.8|54|24.9").</p>
|
||||||
</req>
|
</req>
|
||||||
<import-params method='services/caches/search/all'/>
|
<opt name='location_source' default='default-coords'>
|
||||||
<common-format-params/>
|
Same as in the <a href="%OKAPI:methodargref:services/caches/search/nearest#location_source%">
|
||||||
<returns>
|
services/caches/search/nearest</a> method.
|
||||||
<p>Same format as in the search/all method.</p>
|
</opt>
|
||||||
</returns>
|
<import-params method='services/caches/search/all'/>
|
||||||
|
<common-format-params/>
|
||||||
|
<returns>
|
||||||
|
<p>Same format as in the search/all method.</p>
|
||||||
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
|
|||||||
@@ -13,165 +13,165 @@ use okapi\Db;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns one of: array('cache_code', 'OPXXXX'), array('internal_id', '12345'),
|
* Returns one of: array('cache_code', 'OPXXXX'), array('internal_id', '12345'),
|
||||||
* array('uuid', 'A408C3...') or null.
|
* array('uuid', 'A408C3...') or null.
|
||||||
*/
|
*/
|
||||||
private static function get_cache_key($url)
|
private static function get_cache_key($url)
|
||||||
{
|
{
|
||||||
# Determine our own domain.
|
# Determine our own domain.
|
||||||
|
|
||||||
static $host = null;
|
static $host = null;
|
||||||
static $length = null;
|
static $length = null;
|
||||||
if ($host == null)
|
if ($host == null)
|
||||||
{
|
{
|
||||||
$host = parse_url(Settings::get('SITE_URL'), PHP_URL_HOST);
|
$host = parse_url(Settings::get('SITE_URL'), PHP_URL_HOST);
|
||||||
if (strpos($host, "www.") === 0)
|
if (strpos($host, "www.") === 0)
|
||||||
$host = substr($host, 4);
|
$host = substr($host, 4);
|
||||||
$length = strlen($host);
|
$length = strlen($host);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Parse the URL
|
# Parse the URL
|
||||||
|
|
||||||
$uri = parse_url($url);
|
$uri = parse_url($url);
|
||||||
if ($uri == false)
|
if ($uri == false)
|
||||||
return null;
|
return null;
|
||||||
if ((!isset($uri['scheme'])) || (!in_array($uri['scheme'], array('http', 'https'))))
|
if ((!isset($uri['scheme'])) || (!in_array($uri['scheme'], array('http', 'https'))))
|
||||||
return null;
|
return null;
|
||||||
if ((!isset($uri['host'])) || (substr($uri['host'], -$length) != $host))
|
if ((!isset($uri['host'])) || (substr($uri['host'], -$length) != $host))
|
||||||
return null;
|
return null;
|
||||||
if (!isset($uri['path']))
|
if (!isset($uri['path']))
|
||||||
return null;
|
return null;
|
||||||
if (preg_match("#^/(O[A-Z][A-Z0-9]{4,5})$#", $uri['path'], $matches))
|
if (preg_match("#^/(O[A-Z][A-Z0-9]{4,5})$#", $uri['path'], $matches))
|
||||||
{
|
{
|
||||||
# Some servers allow "http://oc.xx/<cache_code>" shortcut.
|
# Some servers allow "http://oc.xx/<cache_code>" shortcut.
|
||||||
return array('cache_code', $matches[1]);
|
return array('cache_code', $matches[1]);
|
||||||
}
|
}
|
||||||
$parts = array();
|
$parts = array();
|
||||||
if (isset($uri['query']))
|
if (isset($uri['query']))
|
||||||
$parts = array_merge($parts, explode('&', $uri['query']));
|
$parts = array_merge($parts, explode('&', $uri['query']));
|
||||||
if (isset($uri['fragment']))
|
if (isset($uri['fragment']))
|
||||||
$parts = array_merge($parts, explode('&', $uri['fragment']));
|
$parts = array_merge($parts, explode('&', $uri['fragment']));
|
||||||
foreach ($parts as $param)
|
foreach ($parts as $param)
|
||||||
{
|
{
|
||||||
$item = explode('=', $param, 2);
|
$item = explode('=', $param, 2);
|
||||||
if (count($item) != 2)
|
if (count($item) != 2)
|
||||||
continue;
|
continue;
|
||||||
$key = $item[0];
|
$key = $item[0];
|
||||||
$value = $item[1];
|
$value = $item[1];
|
||||||
if ($key == 'wp')
|
if ($key == 'wp')
|
||||||
return array('cache_code', $value);
|
return array('cache_code', $value);
|
||||||
if ($key == 'cacheid')
|
if ($key == 'cacheid')
|
||||||
return array('internal_id', $value);
|
return array('internal_id', $value);
|
||||||
if ($key == 'uuid')
|
if ($key == 'uuid')
|
||||||
return array('uuid', $value);
|
return array('uuid', $value);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# Retrieve the list of URLs to check.
|
# Retrieve the list of URLs to check.
|
||||||
|
|
||||||
$tmp = $request->get_parameter('urls');
|
$tmp = $request->get_parameter('urls');
|
||||||
if (!$tmp)
|
if (!$tmp)
|
||||||
throw new ParamMissing('urls');
|
throw new ParamMissing('urls');
|
||||||
$urls = explode('|', $tmp);
|
$urls = explode('|', $tmp);
|
||||||
$as_dict = $request->get_parameter('as_dict');
|
$as_dict = $request->get_parameter('as_dict');
|
||||||
if (!$as_dict) $as_dict = 'false';
|
if (!$as_dict) $as_dict = 'false';
|
||||||
if (!in_array($as_dict, array('true', 'false')))
|
if (!in_array($as_dict, array('true', 'false')))
|
||||||
throw new InvalidParam('as_dict');
|
throw new InvalidParam('as_dict');
|
||||||
$as_dict = ($as_dict == 'true');
|
$as_dict = ($as_dict == 'true');
|
||||||
|
|
||||||
# Generate the lists of keys.
|
# Generate the lists of keys.
|
||||||
|
|
||||||
$results = array();
|
$results = array();
|
||||||
$urls_with = array(
|
$urls_with = array(
|
||||||
'cache_code' => array(),
|
'cache_code' => array(),
|
||||||
'internal_id' => array(),
|
'internal_id' => array(),
|
||||||
'uuid' => array()
|
'uuid' => array()
|
||||||
);
|
);
|
||||||
foreach ($urls as &$url_ref)
|
foreach ($urls as &$url_ref)
|
||||||
{
|
{
|
||||||
$key = self::get_cache_key($url_ref);
|
$key = self::get_cache_key($url_ref);
|
||||||
if ($key != null)
|
if ($key != null)
|
||||||
$urls_with[$key[0]][$url_ref] = $key[1];
|
$urls_with[$key[0]][$url_ref] = $key[1];
|
||||||
else
|
else
|
||||||
$results[$url_ref] = null;
|
$results[$url_ref] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Include 'cache_code' references.
|
# Include 'cache_code' references.
|
||||||
|
|
||||||
foreach ($urls_with['cache_code'] as $url => $cache_code)
|
foreach ($urls_with['cache_code'] as $url => $cache_code)
|
||||||
$results[$url] = $cache_code;
|
$results[$url] = $cache_code;
|
||||||
|
|
||||||
# Include 'internal_id' references.
|
# Include 'internal_id' references.
|
||||||
|
|
||||||
$internal_ids = array_values($urls_with['internal_id']);
|
$internal_ids = array_values($urls_with['internal_id']);
|
||||||
if (count($internal_ids) > 0)
|
if (count($internal_ids) > 0)
|
||||||
{
|
{
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select cache_id, wp_oc
|
select cache_id, wp_oc
|
||||||
from caches
|
from caches
|
||||||
where
|
where
|
||||||
cache_id in ('".implode("','", array_map('mysql_real_escape_string', $internal_ids))."')
|
cache_id in ('".implode("','", array_map('mysql_real_escape_string', $internal_ids))."')
|
||||||
and status in (1,2,3)
|
and status in (1,2,3)
|
||||||
");
|
");
|
||||||
$dict = array();
|
$dict = array();
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
$dict[$row['cache_id']] = $row['wp_oc'];
|
$dict[$row['cache_id']] = $row['wp_oc'];
|
||||||
foreach ($urls_with['internal_id'] as $url => $internal_id)
|
foreach ($urls_with['internal_id'] as $url => $internal_id)
|
||||||
{
|
{
|
||||||
if (isset($dict[$internal_id]))
|
if (isset($dict[$internal_id]))
|
||||||
$results[$url] = $dict[$internal_id];
|
$results[$url] = $dict[$internal_id];
|
||||||
else
|
else
|
||||||
$results[$url] = null;
|
$results[$url] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Include 'uuid' references.
|
# Include 'uuid' references.
|
||||||
|
|
||||||
$uuids = array_values($urls_with['uuid']);
|
$uuids = array_values($urls_with['uuid']);
|
||||||
if (count($uuids) > 0)
|
if (count($uuids) > 0)
|
||||||
{
|
{
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select uuid, wp_oc
|
select uuid, wp_oc
|
||||||
from caches
|
from caches
|
||||||
where
|
where
|
||||||
uuid in ('".implode("','", array_map('mysql_real_escape_string', $uuids))."')
|
uuid in ('".implode("','", array_map('mysql_real_escape_string', $uuids))."')
|
||||||
and status in (1,2,3)
|
and status in (1,2,3)
|
||||||
");
|
");
|
||||||
$dict = array();
|
$dict = array();
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
$dict[$row['uuid']] = $row['wp_oc'];
|
$dict[$row['uuid']] = $row['wp_oc'];
|
||||||
foreach ($urls_with['uuid'] as $url => $uuid)
|
foreach ($urls_with['uuid'] as $url => $uuid)
|
||||||
{
|
{
|
||||||
if (isset($dict[$uuid]))
|
if (isset($dict[$uuid]))
|
||||||
$results[$url] = $dict[$uuid];
|
$results[$url] = $dict[$uuid];
|
||||||
else
|
else
|
||||||
$results[$url] = null;
|
$results[$url] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Format the results according to the 'as_dict' parameter.
|
# Format the results according to the 'as_dict' parameter.
|
||||||
|
|
||||||
if ($as_dict)
|
if ($as_dict)
|
||||||
return Okapi::formatted_response($request, $results);
|
return Okapi::formatted_response($request, $results);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$cache_codes = array();
|
$cache_codes = array();
|
||||||
foreach ($results as $url => $cache_code)
|
foreach ($results as $url => $cache_code)
|
||||||
if ($cache_code != null)
|
if ($cache_code != null)
|
||||||
$cache_codes[$cache_code] = true;
|
$cache_codes[$cache_code] = true;
|
||||||
$flattened = array('results' => array_keys($cache_codes));
|
$flattened = array('results' => array_keys($cache_codes));
|
||||||
return Okapi::formatted_response($request, $flattened);
|
return Okapi::formatted_response($request, $flattened);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Resolve cache references from given URLs</brief>
|
<brief>Resolve cache references from given URLs</brief>
|
||||||
<issue-id>116</issue-id>
|
<issue-id>116</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Given a set of URLs, determine codes of geocaches referenced within them.</p>
|
<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
|
<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
|
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,
|
on a cache using OKAPI). Geocache pages may be referenced using various types of URLs,
|
||||||
only some of them contain the cache code.</p>
|
only some of them contain the cache code.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='urls'>
|
<req name='urls'>
|
||||||
<p>Pipe-separated list of URLs. No more than 500.</p>
|
<p>Pipe-separated list of URLs. No more than 500.</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='as_dict' default='false'>
|
<opt name='as_dict' default='false'>
|
||||||
<p>If <b>false</b>, then the result of this method will be compatible with
|
<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>
|
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
|
<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
|
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>
|
(cache code) or null (if no cache code was found for the given URL).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>As described in the <b>as_dict</b> parameter.</p>
|
<p>As described in the <b>as_dict</b> parameter.</p>
|
||||||
<p>Examples:</p>
|
<p>Examples:</p>
|
||||||
<p>For <i>by_urls?urls=url1|url2|url3</i>
|
<p>For <i>by_urls?urls=url1|url2|url3</i>
|
||||||
query, the result might look something link this:</p>
|
query, the result might look something link this:</p>
|
||||||
<pre>{"results": ["OP28F9"]}</pre>
|
<pre>{"results": ["OP28F9"]}</pre>
|
||||||
<p>For <i>by_urls?urls=url1|url2|url3&as_dict=true</i>
|
<p>For <i>by_urls?urls=url1|url2|url3&as_dict=true</i>
|
||||||
query, the result might look something link this:</p>
|
query, the result might look something link this:</p>
|
||||||
<pre>{"url1": "OP28F9", "url2": null, "url3": "OP28F9"}</pre>
|
<pre>{"url1": "OP28F9", "url2": null, "url3": "OP28F9"}</pre>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
|
|||||||
@@ -12,75 +12,82 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# You may wonder, why there are no parameters like "bbox" or "center" in the
|
# 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.
|
# "search/all" method. This is *intentional* and should be kept this way.
|
||||||
# Such parameters would fall in conflict with each other and - in result -
|
# Such parameters would fall in conflict with each other and - in result -
|
||||||
# make the documentation very fuzzy. That's why they were intentionally
|
# make the documentation very fuzzy. That's why they were intentionally
|
||||||
# left out of the "search/all" method, and put in separate (individual) ones.
|
# left out of the "search/all" method, and put in separate (individual) ones.
|
||||||
# It's much easier to grasp their meaning this way.
|
# It's much easier to grasp their meaning this way.
|
||||||
|
|
||||||
$tmp = $request->get_parameter('center');
|
$tmp = $request->get_parameter('center');
|
||||||
if (!$tmp)
|
if (!$tmp)
|
||||||
throw new ParamMissing('center');
|
throw new ParamMissing('center');
|
||||||
$parts = explode('|', $tmp);
|
$parts = explode('|', $tmp);
|
||||||
if (count($parts) != 2)
|
if (count($parts) != 2)
|
||||||
throw new InvalidParam('center', "Expecting 2 pipe-separated parts, got ".count($parts).".");
|
throw new InvalidParam('center', "Expecting 2 pipe-separated parts, got ".count($parts).".");
|
||||||
foreach ($parts as &$part_ref)
|
foreach ($parts as &$part_ref)
|
||||||
{
|
{
|
||||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $part_ref))
|
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $part_ref))
|
||||||
throw new InvalidParam('center', "'$part_ref' is not a valid float number.");
|
throw new InvalidParam('center', "'$part_ref' is not a valid float number.");
|
||||||
$part_ref = floatval($part_ref);
|
$part_ref = floatval($part_ref);
|
||||||
}
|
}
|
||||||
list($center_lat, $center_lon) = $parts;
|
list($center_lat, $center_lon) = $parts;
|
||||||
if ($center_lat > 90 || $center_lat < -90)
|
if ($center_lat > 90 || $center_lat < -90)
|
||||||
throw new InvalidParam('center', "Latitudes have to be within -90..90 range.");
|
throw new InvalidParam('center', "Latitudes have to be within -90..90 range.");
|
||||||
if ($center_lon > 180 || $center_lon < -180)
|
if ($center_lon > 180 || $center_lon < -180)
|
||||||
throw new InvalidParam('center', "Longitudes have to be within -180..180 range.");
|
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*
|
# 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
|
# 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.
|
# 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
|
# 'radius' parameter is optional. If not given, we'll have to calculate the
|
||||||
# distance for every cache in the database.
|
# distance for every cache in the database.
|
||||||
|
|
||||||
$where_conds = array();
|
$where_conds = array();
|
||||||
$radius = null;
|
$radius = null;
|
||||||
if ($tmp = $request->get_parameter('radius'))
|
if ($tmp = $request->get_parameter('radius'))
|
||||||
{
|
{
|
||||||
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $tmp))
|
if (!preg_match("/^-?[0-9]+(\.?[0-9]*)$/", $tmp))
|
||||||
throw new InvalidParam('radius', "'$tmp' is not a valid float number.");
|
throw new InvalidParam('radius', "'$tmp' is not a valid float number.");
|
||||||
$radius = floatval($tmp);
|
$radius = floatval($tmp);
|
||||||
if ($radius <= 0)
|
if ($radius <= 0)
|
||||||
throw new InvalidParam('radius', "Has to be a positive number.");
|
throw new InvalidParam('radius', "Has to be a positive number.");
|
||||||
$radius *= 1000; # this one is given in kilemeters, converting to meters!
|
$radius *= 1000; # this one is given in kilemeters, converting to meters!
|
||||||
$where_conds[] = "$distance_formula <= '".mysql_real_escape_string($radius)."'";
|
$where_conds[] = "$distance_formula <= '".mysql_real_escape_string($radius)."'";
|
||||||
}
|
}
|
||||||
|
|
||||||
$search_params = SearchAssistant::get_common_search_params($request);
|
$search_params = $search_assistant->get_search_params();
|
||||||
$search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
|
$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['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);
|
$result = $search_assistant->get_common_search_result();
|
||||||
if ($radius == null)
|
if ($radius == null)
|
||||||
{
|
{
|
||||||
# 'more' is meaningless in this case, we'll remove it.
|
# 'more' is meaningless in this case, we'll remove it.
|
||||||
unset($result['more']);
|
unset($result['more']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,44 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Search for nearest geocaches</brief>
|
<brief>Search for nearest geocaches</brief>
|
||||||
<issue-id>17</issue-id>
|
<issue-id>17</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Find the nearest geocaches. Unless overriden, results are ordered by the distance from
|
<p>Find the nearest geocaches. Unless overriden, results are ordered by the distance from
|
||||||
the given center point.</p>
|
the given center point.</p>
|
||||||
<p>Usually you will want to use search_and_retrieve method instead of this one.
|
<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>
|
This way, you can get much more data in <b>one request</b>.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='center'>
|
<req name='center'>
|
||||||
<p>The center point (typically - the user's location), in the
|
<p>The center point (typically - the user's location), in the
|
||||||
"lat|lon" format.</p>
|
"lat|lon" format.</p>
|
||||||
<p>Use positive numbers for latitudes in the northern hemisphere and
|
<p>Use positive numbers for latitudes in the northern hemisphere and
|
||||||
longitudes in the eastern hemisphere (and negative for southern and
|
longitudes in the eastern hemisphere (and negative for southern and
|
||||||
western hemispheres accordingly). These are full degrees with a dot
|
western hemispheres accordingly). These are full degrees with a dot
|
||||||
as a decimal point (ex. "54.3|22.3").</p>
|
as a decimal point (ex. "54.3|22.3").</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='radius'>
|
<opt name='radius'>
|
||||||
<p>Maximal distance (from the center point) for the cache to
|
<p>Maximal distance (from the center point) for the cache to
|
||||||
be included in the results. Unlike in most other places, this
|
be included in the results. Unlike in most other places, this
|
||||||
distance is given <b>in kilometers</b> instead of meters
|
distance is given <b>in kilometers</b> instead of meters
|
||||||
(it can contain a floating point though).</p>
|
(it can contain a floating point though).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<import-params method='services/caches/search/all'/>
|
<opt name='location_source' default='default-coords'>
|
||||||
<common-format-params/>
|
<p>In general, this parameter should take the same value as in the
|
||||||
<returns>
|
<a href="%OKAPI:methodargref:services/caches/formatters/gpx#location_source%">
|
||||||
<p>Same format as in the search/all method. The <b>more</b> key will
|
services/caches/formatters/gpx</a> method, but currently <u>only two values are
|
||||||
be skipped when no <b>radius</b> argument is given.</p>
|
supported</u>: <b>default-coords</b> and <b>alt_wpt:user-coords</b>.</p>
|
||||||
</returns>
|
|
||||||
|
<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>
|
</xml>
|
||||||
|
|||||||
@@ -14,169 +14,171 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get [set_id, date_created, expires] for the given params_hash
|
* Get [set_id, date_created, expires] for the given params_hash
|
||||||
* (or [null, null, null] if not found).
|
* (or [null, null, null] if not found).
|
||||||
*/
|
*/
|
||||||
private static function find_param_set($params_hash, $ref_max_age)
|
private static function find_param_set($params_hash, $ref_max_age)
|
||||||
{
|
{
|
||||||
$tmp = Db::select_row("
|
$tmp = Db::select_row("
|
||||||
select
|
select
|
||||||
id as id,
|
id as id,
|
||||||
unix_timestamp(date_created) as date_created,
|
unix_timestamp(date_created) as date_created,
|
||||||
unix_timestamp(expires) as expires
|
unix_timestamp(expires) as expires
|
||||||
from okapi_search_sets
|
from okapi_search_sets
|
||||||
where
|
where
|
||||||
params_hash = '".mysql_real_escape_string($params_hash)."'
|
params_hash = '".mysql_real_escape_string($params_hash)."'
|
||||||
and date_add(date_created, interval '".mysql_real_escape_string($ref_max_age)."' second) > now()
|
and date_add(date_created, interval '".mysql_real_escape_string($ref_max_age)."' second) > now()
|
||||||
order by id desc
|
order by id desc
|
||||||
limit 1
|
limit 1
|
||||||
");
|
");
|
||||||
if ($tmp === null)
|
if ($tmp === null)
|
||||||
return array(null, null, null);
|
return array(null, null, null);
|
||||||
return array($tmp['id'], $tmp['date_created'], $tmp['expires']);
|
return array($tmp['id'], $tmp['date_created'], $tmp['expires']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# "Cache control" parameters.
|
# "Cache control" parameters.
|
||||||
|
|
||||||
$tmp = $request->get_parameter('min_store');
|
$tmp = $request->get_parameter('min_store');
|
||||||
if ($tmp === null) $tmp = "300";
|
if ($tmp === null) $tmp = "300";
|
||||||
$min_store = intval($tmp);
|
$min_store = intval($tmp);
|
||||||
if (("$min_store" !== $tmp) ||($min_store < 0) || ($min_store > 64800))
|
if (("$min_store" !== $tmp) ||($min_store < 0) || ($min_store > 64800))
|
||||||
throw new InvalidParam('min_store', "Has to be in the 0..64800 range.");
|
throw new InvalidParam('min_store', "Has to be in the 0..64800 range.");
|
||||||
|
|
||||||
$tmp = $request->get_parameter('ref_max_age');
|
$tmp = $request->get_parameter('ref_max_age');
|
||||||
if ($tmp === null) $tmp = "300";
|
if ($tmp === null) $tmp = "300";
|
||||||
if ($tmp == "nolimit") $tmp = "9999999";
|
if ($tmp == "nolimit") $tmp = "9999999";
|
||||||
$ref_max_age = intval($tmp);
|
$ref_max_age = intval($tmp);
|
||||||
if (("$ref_max_age" !== $tmp) || ($ref_max_age < 300))
|
if (("$ref_max_age" !== $tmp) || ($ref_max_age < 300))
|
||||||
throw new InvalidParam('ref_max_age', "Has to be >=300.");
|
throw new InvalidParam('ref_max_age', "Has to be >=300.");
|
||||||
|
|
||||||
# Search params.
|
# Search params.
|
||||||
|
|
||||||
$search_params = SearchAssistant::get_common_search_params($request);
|
$search_assistant = new SearchAssistant($request);
|
||||||
$tables = array_merge(
|
$search_assistant->prepare_common_search_params();
|
||||||
array('caches'),
|
$search_params = $search_assistant->get_search_params();
|
||||||
$search_params['extra_tables']
|
$tables = array_merge(
|
||||||
);
|
array('caches'),
|
||||||
$where_conds = array_merge(
|
$search_params['extra_tables']
|
||||||
array('caches.wp_oc is not null'),
|
);
|
||||||
$search_params['where_conds']
|
$where_conds = array_merge(
|
||||||
);
|
array('caches.wp_oc is not null'),
|
||||||
unset($search_params);
|
$search_params['where_conds']
|
||||||
|
);
|
||||||
|
unset($search_params);
|
||||||
|
|
||||||
# Generate, or retrieve an existing set, and return the result.
|
# Generate, or retrieve an existing set, and return the result.
|
||||||
# All user-supplied data in $tables and $where_conds MUST be escaped!
|
# All user-supplied data in $tables and $where_conds MUST be escaped!
|
||||||
|
|
||||||
$result = self::get_set($tables, $where_conds, $min_store, $ref_max_age);
|
$result = self::get_set($tables, $where_conds, $min_store, $ref_max_age);
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Important: YOU HAVE TO make sure $tables and $where_conds don't contain
|
* Important: YOU HAVE TO make sure $tables and $where_conds don't contain
|
||||||
* unescaped user-supplied data!
|
* unescaped user-supplied data!
|
||||||
*/
|
*/
|
||||||
public static function get_set($tables, $where_conds, $min_store, $ref_max_age)
|
public static function get_set($tables, $where_conds, $min_store, $ref_max_age)
|
||||||
{
|
{
|
||||||
# Compute the "params hash".
|
# 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
|
# Check if there exists an entry for this hash, which also meets the
|
||||||
# given freshness criteria.
|
# given freshness criteria.
|
||||||
|
|
||||||
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
||||||
if ($set_id === null)
|
if ($set_id === null)
|
||||||
{
|
{
|
||||||
# To avoid generating the same results by multiple threads at once
|
# To avoid generating the same results by multiple threads at once
|
||||||
# (the "tile" method uses the "save" method, so the problem is
|
# (the "tile" method uses the "save" method, so the problem is
|
||||||
# quite real!), we will acquire a write-lock here.
|
# quite real!), we will acquire a write-lock here.
|
||||||
|
|
||||||
$lock = OkapiLock::get("search-results-writer");
|
$lock = OkapiLock::get("search-results-writer");
|
||||||
$lock->acquire();
|
$lock->acquire();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
# Make sure we were the first to acquire the lock.
|
# 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);
|
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
||||||
if ($set_id === null)
|
if ($set_id === null)
|
||||||
{
|
{
|
||||||
# We are in the first thread which have acquired the lock.
|
# We are in the first thread which have acquired the lock.
|
||||||
# We will proceed with result-set creation. Other threads
|
# We will proceed with result-set creation. Other threads
|
||||||
# will be waiting until we finish.
|
# will be waiting until we finish.
|
||||||
|
|
||||||
Db::execute("
|
Db::execute("
|
||||||
insert into okapi_search_sets (params_hash, date_created, expires)
|
insert into okapi_search_sets (params_hash, date_created, expires)
|
||||||
values (
|
values (
|
||||||
'processing in progress',
|
'processing in progress',
|
||||||
now(),
|
now(),
|
||||||
date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
$set_id = Db::last_insert_id();
|
$set_id = Db::last_insert_id();
|
||||||
$date_created = time();
|
$date_created = time();
|
||||||
$expires = $date_created + $min_store + 60;
|
$expires = $date_created + $min_store + 60;
|
||||||
Db::execute("
|
Db::execute("
|
||||||
insert into okapi_search_results (set_id, cache_id)
|
insert into okapi_search_results (set_id, cache_id)
|
||||||
select distinct
|
select distinct
|
||||||
'".mysql_real_escape_string($set_id)."',
|
'".mysql_real_escape_string($set_id)."',
|
||||||
caches.cache_id
|
caches.cache_id
|
||||||
from ".implode(", ", $tables)."
|
from ".implode(", ", $tables)."
|
||||||
where (".implode(") and (", $where_conds).")
|
where (".implode(") and (", $where_conds).")
|
||||||
");
|
");
|
||||||
|
|
||||||
# Lock barrier, to make sure the data is visible by other
|
# Lock barrier, to make sure the data is visible by other
|
||||||
# sessions. See http://bugs.mysql.com/bug.php?id=36618
|
# sessions. See http://bugs.mysql.com/bug.php?id=36618
|
||||||
|
|
||||||
Db::execute("lock table okapi_search_results write");
|
Db::execute("lock table okapi_search_results write");
|
||||||
Db::execute("unlock tables");
|
Db::execute("unlock tables");
|
||||||
|
|
||||||
Db::execute("
|
Db::execute("
|
||||||
update okapi_search_sets
|
update okapi_search_sets
|
||||||
set params_hash = '".mysql_real_escape_string($params_hash)."'
|
set params_hash = '".mysql_real_escape_string($params_hash)."'
|
||||||
where id = '".mysql_real_escape_string($set_id)."'
|
where id = '".mysql_real_escape_string($set_id)."'
|
||||||
");
|
");
|
||||||
} else {
|
} else {
|
||||||
# Some other thread acquired the lock before us and it has
|
# Some other thread acquired the lock before us and it has
|
||||||
# generated the result set. We don't need to do anything.
|
# generated the result set. We don't need to do anything.
|
||||||
}
|
}
|
||||||
$lock->release();
|
$lock->release();
|
||||||
}
|
}
|
||||||
catch (Exception $e)
|
catch (Exception $e)
|
||||||
{
|
{
|
||||||
# SQL error? Make sure the lock is released and rethrow.
|
# SQL error? Make sure the lock is released and rethrow.
|
||||||
|
|
||||||
$lock->release();
|
$lock->release();
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# If we got an old set, we may need to expand its lifetime in order to
|
# If we got an old set, we may need to expand its lifetime in order to
|
||||||
# meet user's "min_store" criterium.
|
# meet user's "min_store" criterium.
|
||||||
|
|
||||||
if (time() + $min_store > $expires)
|
if (time() + $min_store > $expires)
|
||||||
{
|
{
|
||||||
Db::execute("
|
Db::execute("
|
||||||
update okapi_search_sets
|
update okapi_search_sets
|
||||||
set expires = date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
set expires = date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
||||||
where id = '".mysql_real_escape_string($set_id)."'
|
where id = '".mysql_real_escape_string($set_id)."'
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'set_id' => "$set_id",
|
'set_id' => "$set_id",
|
||||||
'generated_at' => date('c', $date_created),
|
'generated_at' => date('c', $date_created),
|
||||||
'expires' => date('c', $expires),
|
'expires' => date('c', $expires),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Save a search result set</brief>
|
<brief>Save a search result set</brief>
|
||||||
<issue-id>163</issue-id>
|
<issue-id>163</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This works similar to the <b>search/all</b> method, but the returned
|
<p>This works similar to the <b>search/all</b> method, but the returned
|
||||||
set of geocaches is temporarilly stored, instead of being directly
|
set of geocaches is temporarilly stored, instead of being directly
|
||||||
returned to you.</p>
|
returned to you.</p>
|
||||||
<p>You may want to use this method when you don't want your search
|
<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.
|
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>
|
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> (!)
|
method with proper <b>set_and</b> <u>and <b>status</b></u> (!)
|
||||||
parameters.</p>
|
parameters.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<opt name='min_store' default="300">
|
<opt name='min_store' default="300">
|
||||||
The amount of time (in seconds) after which you allow OKAPI to delete
|
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 set (OKAPI <b>may</b> remove it, but doesn't have to).
|
||||||
The maximum allowed value is 64800 (18 hours).
|
The maximum allowed value is 64800 (18 hours).
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='ref_max_age' default="300">
|
<opt name='ref_max_age' default="300">
|
||||||
<p>If OKAPI finds an existing result set which was created for your
|
<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
|
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
|
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>
|
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
|
<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>
|
<b>nolimit</b> value. It must be greater or equal to 300 (5 minutes).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<import-params method='services/caches/search/all' except="offset|limit|order_by"/>
|
<import-params method='services/caches/search/all' except="offset|limit|order_by"/>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>set_id</b> - string, the identifier of your saved set,
|
<li><b>set_id</b> - string, the identifier of your saved set,
|
||||||
for future reference.</li>
|
for future reference.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,109 +13,109 @@ use okapi\BadRequest;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
# Check search method
|
# Check search method
|
||||||
$search_method = $request->get_parameter('search_method');
|
$search_method = $request->get_parameter('search_method');
|
||||||
if (!$search_method)
|
if (!$search_method)
|
||||||
throw new ParamMissing('search_method');
|
throw new ParamMissing('search_method');
|
||||||
if (strpos($search_method, "services/caches/search/") !== 0)
|
if (strpos($search_method, "services/caches/search/") !== 0)
|
||||||
throw new InvalidParam('search_method', "Should begin with 'services/caches/search/'.");
|
throw new InvalidParam('search_method', "Should begin with 'services/caches/search/'.");
|
||||||
if (!OkapiServiceRunner::exists($search_method))
|
if (!OkapiServiceRunner::exists($search_method))
|
||||||
throw new InvalidParam('search_method', "Method does not exist: '$search_method'");
|
throw new InvalidParam('search_method', "Method does not exist: '$search_method'");
|
||||||
$search_params = $request->get_parameter('search_params');
|
$search_params = $request->get_parameter('search_params');
|
||||||
if (!$search_params)
|
if (!$search_params)
|
||||||
throw new ParamMissing('search_params');
|
throw new ParamMissing('search_params');
|
||||||
$search_params = json_decode($search_params, true);
|
$search_params = json_decode($search_params, true);
|
||||||
if (!is_array($search_params))
|
if (!is_array($search_params))
|
||||||
throw new InvalidParam('search_params', "Should be a JSON-encoded dictionary");
|
throw new InvalidParam('search_params', "Should be a JSON-encoded dictionary");
|
||||||
|
|
||||||
# Check retrieval method
|
# Check retrieval method
|
||||||
$retr_method = $request->get_parameter('retr_method');
|
$retr_method = $request->get_parameter('retr_method');
|
||||||
if (!$retr_method)
|
if (!$retr_method)
|
||||||
throw new ParamMissing('retr_method');
|
throw new ParamMissing('retr_method');
|
||||||
if (!OkapiServiceRunner::exists($retr_method))
|
if (!OkapiServiceRunner::exists($retr_method))
|
||||||
throw new InvalidParam('retr_method', "Method does not exist: '$retr_method'");
|
throw new InvalidParam('retr_method', "Method does not exist: '$retr_method'");
|
||||||
$retr_params = $request->get_parameter('retr_params');
|
$retr_params = $request->get_parameter('retr_params');
|
||||||
if (!$retr_params)
|
if (!$retr_params)
|
||||||
throw new ParamMissing('retr_params');
|
throw new ParamMissing('retr_params');
|
||||||
$retr_params = json_decode($retr_params, true);
|
$retr_params = json_decode($retr_params, true);
|
||||||
if (!is_array($retr_params))
|
if (!is_array($retr_params))
|
||||||
throw new InvalidParam('retr_params', "Should be a JSON-encoded dictionary");
|
throw new InvalidParam('retr_params', "Should be a JSON-encoded dictionary");
|
||||||
|
|
||||||
self::map_values_to_strings($search_params);
|
self::map_values_to_strings($search_params);
|
||||||
self::map_values_to_strings($retr_params);
|
self::map_values_to_strings($retr_params);
|
||||||
|
|
||||||
# Wrapped?
|
# Wrapped?
|
||||||
$wrap = $request->get_parameter('wrap');
|
$wrap = $request->get_parameter('wrap');
|
||||||
if ($wrap == null) throw new ParamMissing('wrap');
|
if ($wrap == null) throw new ParamMissing('wrap');
|
||||||
if (!in_array($wrap, array('true', 'false')))
|
if (!in_array($wrap, array('true', 'false')))
|
||||||
throw new InvalidParam('wrap');
|
throw new InvalidParam('wrap');
|
||||||
$wrap = ($wrap == 'true');
|
$wrap = ($wrap == 'true');
|
||||||
|
|
||||||
# Run search method
|
# Run search method
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$search_result = OkapiServiceRunner::call($search_method, new OkapiInternalRequest(
|
$search_result = OkapiServiceRunner::call($search_method, new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, $search_params));
|
$request->consumer, $request->token, $search_params));
|
||||||
}
|
}
|
||||||
catch (BadRequest $e)
|
catch (BadRequest $e)
|
||||||
{
|
{
|
||||||
throw new InvalidParam('search_params', "Search method responded with the ".
|
throw new InvalidParam('search_params', "Search method responded with the ".
|
||||||
"following error message: ".$e->getMessage());
|
"following error message: ".$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run retrieval method
|
# Run retrieval method
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$retr_result = OkapiServiceRunner::call($retr_method, new OkapiInternalRequest(
|
$retr_result = OkapiServiceRunner::call($retr_method, new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array_merge($retr_params,
|
$request->consumer, $request->token, array_merge($retr_params,
|
||||||
array('cache_codes' => implode("|", $search_result['results'])))));
|
array('cache_codes' => implode("|", $search_result['results'])))));
|
||||||
}
|
}
|
||||||
catch (BadRequest $e)
|
catch (BadRequest $e)
|
||||||
{
|
{
|
||||||
throw new InvalidParam('retr_params', "Retrieval method responded with the ".
|
throw new InvalidParam('retr_params', "Retrieval method responded with the ".
|
||||||
"following error message: ".$e->getMessage());
|
"following error message: ".$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($wrap)
|
if ($wrap)
|
||||||
{
|
{
|
||||||
# $retr_result might be a PHP object, but also might be a binary response
|
# $retr_result might be a PHP object, but also might be a binary response
|
||||||
# (e.g. a GPX file).
|
# (e.g. a GPX file).
|
||||||
if ($retr_result instanceof OkapiHttpResponse)
|
if ($retr_result instanceof OkapiHttpResponse)
|
||||||
$result = array('results' => $retr_result->get_body());
|
$result = array('results' => $retr_result->get_body());
|
||||||
else
|
else
|
||||||
$result = array('results' => $retr_result);
|
$result = array('results' => $retr_result);
|
||||||
foreach ($search_result as $key => &$value_ref)
|
foreach ($search_result as $key => &$value_ref)
|
||||||
if ($key != 'results')
|
if ($key != 'results')
|
||||||
$result[$key] = $value_ref;
|
$result[$key] = $value_ref;
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ($retr_result instanceof OkapiHttpResponse)
|
if ($retr_result instanceof OkapiHttpResponse)
|
||||||
return $retr_result;
|
return $retr_result;
|
||||||
else
|
else
|
||||||
return Okapi::formatted_response($request, $retr_result);
|
return Okapi::formatted_response($request, $retr_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function map_values_to_strings(&$dict)
|
private static function map_values_to_strings(&$dict)
|
||||||
{
|
{
|
||||||
foreach (array_keys($dict) as $key)
|
foreach (array_keys($dict) as $key)
|
||||||
{
|
{
|
||||||
$val = $dict[$key];
|
$val = $dict[$key];
|
||||||
if (is_numeric($val) || is_string($val))
|
if (is_numeric($val) || is_string($val))
|
||||||
$dict[$key] = (string)$val;
|
$dict[$key] = (string)$val;
|
||||||
else
|
else
|
||||||
throw new BadRequest("Invalid value format for key: ".$key);
|
throw new BadRequest("Invalid value format for key: ".$key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,65 +1,65 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Search for caches and retrieve formatted results</brief>
|
<brief>Search for caches and retrieve formatted results</brief>
|
||||||
<issue-id>18</issue-id>
|
<issue-id>18</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>We think that searching and retrieving data are two different things
|
<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
|
and that's why they were cleanly separated in the documentation (put in
|
||||||
separate methods). This was done primarily to keep the docs clean.
|
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>
|
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.
|
<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
|
Then you have to use other method (like services/caches/geocaches) to
|
||||||
retrieve the names and locations, based on those cache codes. The
|
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
|
<b>search_and_retrieve</b> method allows you to do these two steps in one
|
||||||
method call.</p>
|
method call.</p>
|
||||||
<p>First, you have to choose both methods and their parameters - one method
|
<p>First, you have to choose both methods and their parameters - one method
|
||||||
which returns the cache codes, and the other one, that responds
|
which returns the cache codes, and the other one, that responds
|
||||||
with additional data for the given caches.</p>
|
with additional data for the given caches.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='search_method'>
|
<req name='search_method'>
|
||||||
<p>Name of the search method (begin with "services/").</p>
|
<p>Name of the search method (begin with "services/").</p>
|
||||||
<p>E.g. <i>services/caches/search/nearest</i>.</p>
|
<p>E.g. <i>services/caches/search/nearest</i>.</p>
|
||||||
</req>
|
</req>
|
||||||
<req name='search_params'>
|
<req name='search_params'>
|
||||||
<p>JSON-formatted dictionary of parameters to be passed on
|
<p>JSON-formatted dictionary of parameters to be passed on
|
||||||
to the search method.</p>
|
to the search method.</p>
|
||||||
<p>E.g. <i>{"center": "49|19", "status": "Available"}</i>.</p>
|
<p>E.g. <i>{"center": "49|19", "status": "Available"}</i>.</p>
|
||||||
</req>
|
</req>
|
||||||
<req name='retr_method'>
|
<req name='retr_method'>
|
||||||
<p>Name of the retrieval method (begin with "services/").</p>
|
<p>Name of the retrieval method (begin with "services/").</p>
|
||||||
<p>E.g. <i>services/caches/geocaches</i>.</p>
|
<p>E.g. <i>services/caches/geocaches</i>.</p>
|
||||||
</req>
|
</req>
|
||||||
<req name='retr_params'>
|
<req name='retr_params'>
|
||||||
<p>JSON-formatted dictionary of parameters to be passed on
|
<p>JSON-formatted dictionary of parameters to be passed on
|
||||||
to the retrieval method.</p>
|
to the retrieval method.</p>
|
||||||
<p>E.g. <i>{"fields": "name|location|type"}</i></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>.
|
<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>
|
These will be the cache codes collected from the results of the search method.</p>
|
||||||
</req>
|
</req>
|
||||||
<req name='wrap'>
|
<req name='wrap'>
|
||||||
<p>Boolean.</p>
|
<p>Boolean.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>If <b>true</b>, then results will be wrapped in an additional
|
<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
|
object, in order to include any additional data received along with the
|
||||||
search_method response (i.e. the <b>more</b> value).</li>
|
search_method response (i.e. the <b>more</b> value).</li>
|
||||||
<li>If <b>false</b>, then this method will return exactly what the
|
<li>If <b>false</b>, then this method will return exactly what the
|
||||||
<b>retr_method</b> will respond with.</li>
|
<b>retr_method</b> will respond with.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</req>
|
</req>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>If <b>wrap</b> is <b>true</b>, then the method will return a
|
<p>If <b>wrap</b> is <b>true</b>, then the method will return a
|
||||||
dictionary of the following structure:</p>
|
dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>results</b> - anything the retrival method
|
<li><b>results</b> - anything the retrival method
|
||||||
responds with (as long as it's not an error).</li>
|
responds with (as long as it's not an error).</li>
|
||||||
<li>any extra keys and values received as a response of
|
<li>any extra keys and values received as a response of
|
||||||
the search_method (i.e. the <b>more</b> variable).</li>
|
the search_method (i.e. the <b>more</b> variable).</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>If <b>wrap</b> is <b>false</b>, then the method will return
|
<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>
|
anything the retrieval methods responds with (along with its HTTP headers).</p>
|
||||||
<p><b>Example:</b></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>
|
<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>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>
|
<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>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -15,149 +15,149 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static $valid_field_names = array(
|
private static $valid_field_names = array(
|
||||||
'uuid', 'cache_code', 'date', 'user', 'type', 'was_recommended', 'comment',
|
'uuid', 'cache_code', 'date', 'user', 'type', 'was_recommended', 'comment',
|
||||||
'images', 'internal_id', 'oc_team_entry',
|
'images', 'internal_id', 'oc_team_entry',
|
||||||
);
|
);
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$log_uuids = $request->get_parameter('log_uuids');
|
$log_uuids = $request->get_parameter('log_uuids');
|
||||||
if ($log_uuids === null) throw new ParamMissing('log_uuids');
|
if ($log_uuids === null) throw new ParamMissing('log_uuids');
|
||||||
if ($log_uuids === "")
|
if ($log_uuids === "")
|
||||||
{
|
{
|
||||||
$log_uuids = array();
|
$log_uuids = array();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
$log_uuids = explode("|", $log_uuids);
|
$log_uuids = explode("|", $log_uuids);
|
||||||
|
|
||||||
if ((count($log_uuids) > 500) && (!$request->skip_limits))
|
if ((count($log_uuids) > 500) && (!$request->skip_limits))
|
||||||
throw new InvalidParam('log_uuids', "Maximum allowed number of referenced ".
|
throw new InvalidParam('log_uuids', "Maximum allowed number of referenced ".
|
||||||
"log entries is 500. You provided ".count($log_uuids)." UUIDs.");
|
"log entries is 500. You provided ".count($log_uuids)." UUIDs.");
|
||||||
if (count($log_uuids) != count(array_unique($log_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).");
|
throw new InvalidParam('log_uuids', "Duplicate UUIDs detected (make sure each UUID is referenced only once).");
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields) $fields = "date|user|type|comment";
|
if (!$fields) $fields = "date|user|type|comment";
|
||||||
$fields = explode("|", $fields);
|
$fields = explode("|", $fields);
|
||||||
foreach ($fields as $field)
|
foreach ($fields as $field)
|
||||||
if (!in_array($field, self::$valid_field_names))
|
if (!in_array($field, self::$valid_field_names))
|
||||||
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
||||||
|
|
||||||
if (Settings::get('OC_BRANCH') == 'oc.de')
|
if (Settings::get('OC_BRANCH') == 'oc.de')
|
||||||
{
|
{
|
||||||
$teamentry_field = 'cl.oc_team_comment';
|
$teamentry_field = 'cl.oc_team_comment';
|
||||||
$ratingdate_condition = 'and cr.rating_date=cl.date';
|
$ratingdate_condition = 'and cr.rating_date=cl.date';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$teamentry_field = '(cl.type=12)';
|
$teamentry_field = '(cl.type=12)';
|
||||||
$ratingdate_condition = '';
|
$ratingdate_condition = '';
|
||||||
}
|
}
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select
|
select
|
||||||
cl.id, c.wp_oc as cache_code, cl.uuid, cl.type,
|
cl.id, c.wp_oc as cache_code, cl.uuid, cl.type,
|
||||||
".$teamentry_field." as oc_team_entry,
|
".$teamentry_field." as oc_team_entry,
|
||||||
unix_timestamp(cl.date) as date, cl.text,
|
unix_timestamp(cl.date) as date, cl.text,
|
||||||
u.uuid as user_uuid, u.username, u.user_id,
|
u.uuid as user_uuid, u.username, u.user_id,
|
||||||
if(cr.user_id is null, 0, 1) as was_recommended
|
if(cr.user_id is null, 0, 1) as was_recommended
|
||||||
from
|
from
|
||||||
(cache_logs cl,
|
(cache_logs cl,
|
||||||
user u,
|
user u,
|
||||||
caches c)
|
caches c)
|
||||||
left join cache_rating cr
|
left join cache_rating cr
|
||||||
on cr.user_id = u.user_id
|
on cr.user_id = u.user_id
|
||||||
and cr.cache_id = c.cache_id
|
and cr.cache_id = c.cache_id
|
||||||
".$ratingdate_condition."
|
".$ratingdate_condition."
|
||||||
and cl.type in (
|
and cl.type in (
|
||||||
".Okapi::logtypename2id("Found it").",
|
".Okapi::logtypename2id("Found it").",
|
||||||
".Okapi::logtypename2id("Attended")."
|
".Okapi::logtypename2id("Attended")."
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
cl.uuid in ('".implode("','", array_map('mysql_real_escape_string', $log_uuids))."')
|
cl.uuid in ('".implode("','", array_map('mysql_real_escape_string', $log_uuids))."')
|
||||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
||||||
and cl.user_id = u.user_id
|
and cl.user_id = u.user_id
|
||||||
and c.cache_id = cl.cache_id
|
and c.cache_id = cl.cache_id
|
||||||
and c.status in (1,2,3)
|
and c.status in (1,2,3)
|
||||||
");
|
");
|
||||||
$results = array();
|
$results = array();
|
||||||
$log_id2uuid = array(); /* Maps logs' internal_ids to uuids */
|
$log_id2uuid = array(); /* Maps logs' internal_ids to uuids */
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
{
|
{
|
||||||
$results[$row['uuid']] = array(
|
$results[$row['uuid']] = array(
|
||||||
'uuid' => $row['uuid'],
|
'uuid' => $row['uuid'],
|
||||||
'cache_code' => $row['cache_code'],
|
'cache_code' => $row['cache_code'],
|
||||||
'date' => date('c', $row['date']),
|
'date' => date('c', $row['date']),
|
||||||
'user' => array(
|
'user' => array(
|
||||||
'uuid' => $row['user_uuid'],
|
'uuid' => $row['user_uuid'],
|
||||||
'username' => $row['username'],
|
'username' => $row['username'],
|
||||||
'profile_url' => Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id'],
|
'profile_url' => Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id'],
|
||||||
),
|
),
|
||||||
'type' => Okapi::logtypeid2name($row['type']),
|
'type' => Okapi::logtypeid2name($row['type']),
|
||||||
'was_recommended' => $row['was_recommended'] ? true : false,
|
'was_recommended' => $row['was_recommended'] ? true : false,
|
||||||
'comment' => Okapi::fix_oc_html($row['text']),
|
'comment' => Okapi::fix_oc_html($row['text']),
|
||||||
'images' => array(),
|
'images' => array(),
|
||||||
'internal_id' => $row['id'],
|
'internal_id' => $row['id'],
|
||||||
);
|
);
|
||||||
if (in_array('oc_team_entry',$fields))
|
if (in_array('oc_team_entry',$fields))
|
||||||
$results[$row['uuid']]['oc_team_entry'] = $row['oc_team_entry'] ? true : false;
|
$results[$row['uuid']]['oc_team_entry'] = $row['oc_team_entry'] ? true : false;
|
||||||
$log_id2uuid[$row['id']] = $row['uuid'];
|
$log_id2uuid[$row['id']] = $row['uuid'];
|
||||||
}
|
}
|
||||||
mysql_free_result($rs);
|
mysql_free_result($rs);
|
||||||
|
|
||||||
# fetch images
|
# fetch images
|
||||||
|
|
||||||
if (in_array('images', $fields))
|
if (in_array('images', $fields))
|
||||||
{
|
{
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select object_id, uuid, url, title, spoiler
|
select object_id, uuid, url, title, spoiler
|
||||||
from pictures
|
from pictures
|
||||||
where
|
where
|
||||||
object_type = 1
|
object_type = 1
|
||||||
and object_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($log_id2uuid)))."')
|
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 display = 1 /* currently is always 1 for logpix */
|
||||||
and unknown_format = 0
|
and unknown_format = 0
|
||||||
order by date_created
|
order by date_created
|
||||||
");
|
");
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
{
|
{
|
||||||
$results[$log_id2uuid[$row['object_id']]]['images'][] =
|
$results[$log_id2uuid[$row['object_id']]]['images'][] =
|
||||||
array(
|
array(
|
||||||
'uuid' => $row['uuid'],
|
'uuid' => $row['uuid'],
|
||||||
'url' => $row['url'],
|
'url' => $row['url'],
|
||||||
'thumb_url' => Settings::get('SITE_URL') . 'thumbs.php?uuid=' . $row['uuid'],
|
'thumb_url' => Settings::get('SITE_URL') . 'thumbs.php?uuid=' . $row['uuid'],
|
||||||
'caption' => $row['title'],
|
'caption' => $row['title'],
|
||||||
'is_spoiler' => ($row['spoiler'] ? true : false),
|
'is_spoiler' => ($row['spoiler'] ? true : false),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
mysql_free_result($rs);
|
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)
|
foreach ($log_uuids as $log_uuid)
|
||||||
if (!isset($results[$log_uuid]))
|
if (!isset($results[$log_uuid]))
|
||||||
$results[$log_uuid] = null;
|
$results[$log_uuid] = null;
|
||||||
|
|
||||||
# Remove unwanted fields.
|
# Remove unwanted fields.
|
||||||
|
|
||||||
foreach (self::$valid_field_names as $field)
|
foreach (self::$valid_field_names as $field)
|
||||||
if (!in_array($field, $fields))
|
if (!in_array($field, $fields))
|
||||||
foreach ($results as &$result_ref)
|
foreach ($results as &$result_ref)
|
||||||
unset($result_ref[$field]);
|
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();
|
$ordered_results = array();
|
||||||
foreach ($log_uuids as $log_uuid)
|
foreach ($log_uuids as $log_uuid)
|
||||||
$ordered_results[$log_uuid] = $results[$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>
|
<xml>
|
||||||
<brief>Retrieve information on multiple log entries</brief>
|
<brief>Retrieve information on multiple log entries</brief>
|
||||||
<issue-id>107</issue-id>
|
<issue-id>107</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method works like the services/logs/entry method, but works
|
<p>This method works like the services/logs/entry method, but works
|
||||||
with multiple log entries (instead of only one).</p>
|
with multiple log entries (instead of only one).</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='log_uuids'>
|
<req name='log_uuids'>
|
||||||
<p>Pipe-separated list of UUIDs. These represent the log entries you
|
<p>Pipe-separated list of UUIDs. These represent the log entries you
|
||||||
are interested in. No more than 500 codes are allowed.
|
are interested in. No more than 500 codes are allowed.
|
||||||
Unlike in the "entry" method, this CAN be an empty string (it will
|
Unlike in the "entry" method, this CAN be an empty string (it will
|
||||||
result in an empty, but valid, response).</p>
|
result in an empty, but valid, response).</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='fields' default='date|user|type|comment'>
|
<opt name='fields' default='date|user|type|comment'>
|
||||||
<p>Same as in the services/logs/entry method. Pipe-separated list
|
<p>Same as in the services/logs/entry method. Pipe-separated list
|
||||||
of field names which you are interested with.
|
of field names which you are interested with.
|
||||||
See services/logs/entry method for a list of available values.</p>
|
See services/logs/entry method for a list of available values.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary. UUIDs you provide will be mapped to dictionary keys,
|
<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>
|
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.
|
<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
|
(This behavior is different than in the services/logs/entry method, which
|
||||||
responds with an HTTP 400 error in such case.)</p>
|
responds with an HTTP 400 error in such case.)</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -11,26 +11,26 @@ use okapi\InvalidParam;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$log_uuid = $request->get_parameter('log_uuid');
|
$log_uuid = $request->get_parameter('log_uuid');
|
||||||
if (!$log_uuid) throw new ParamMissing('log_uuid');
|
if (!$log_uuid) throw new ParamMissing('log_uuid');
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields) $fields = "date|user|type|comment";
|
if (!$fields) $fields = "date|user|type|comment";
|
||||||
|
|
||||||
$results = OkapiServiceRunner::call('services/logs/entries', new OkapiInternalRequest(
|
$results = OkapiServiceRunner::call('services/logs/entries', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('log_uuids' => $log_uuid,
|
$request->consumer, $request->token, array('log_uuids' => $log_uuid,
|
||||||
'fields' => $fields)));
|
'fields' => $fields)));
|
||||||
$result = $results[$log_uuid];
|
$result = $results[$log_uuid];
|
||||||
if ($result == null)
|
if ($result == null)
|
||||||
throw new InvalidParam('log_uuid', "This log entry does not exist.");
|
throw new InvalidParam('log_uuid', "This log entry does not exist.");
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +1,117 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve information on a single log entry</brief>
|
<brief>Retrieve information on a single log entry</brief>
|
||||||
<issue-id>108</issue-id>
|
<issue-id>108</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Retrieve information on a single log entry.</p>
|
<p>Retrieve information on a single log entry.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='log_uuid'>UUID of the log entry</req>
|
<req name='log_uuid'>UUID of the log entry</req>
|
||||||
<opt name='fields' default='date|user|type|comment'>
|
<opt name='fields' default='date|user|type|comment'>
|
||||||
<p>Pipe-separated list of field names which you are interested with.
|
<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
|
Selected fields will be included in the response. See below fot the list
|
||||||
of available fields.</p>
|
of available fields.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>uuid</b> - unique ID of the log entry,</li>
|
<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><b>cache_code</b> - code of the cache which the log entry refers to,</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>date</b> - date and time (ISO 8601) when the log entry was submitted.</p>
|
<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
|
<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
|
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>
|
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>
|
value contains the "00:00:00" string, then it is date-only.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>user</b> - a dictionary:</p>
|
<p><b>user</b> - a dictionary:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>uuid</b> - ID of the user (author of the log entry),</li>
|
<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>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>
|
<li><b>profile_url</b> - URL of the profile page of the user,</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>type</b> - string; log type. One of the values documented
|
<p><b>type</b> - string; log type. One of the values documented
|
||||||
below.</p>
|
below.</p>
|
||||||
|
|
||||||
<p>Primary types, commonly used by all Opencaching installations:</p>
|
<p>Primary types, commonly used by all Opencaching installations:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>"Found it" - a user found the cache (Non-Event caches).</li>
|
<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>"Didn't find it" - a user searched for, but couldn't find the cache (Non-Event caches).</li>
|
||||||
<li>"Comment".</li>
|
<li>"Comment".</li>
|
||||||
<li>"Will attend" - a user is planning to attend the event (for Event caches only).</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>
|
<li>"Attended" - a user has attended the event (for Event caches only).</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Types which indicate a change of state of the geocache or confirm the
|
<p>Types which indicate a change of state of the geocache or confirm the
|
||||||
current state (used only by some Opencaching installations):</p>
|
current state (used only by some Opencaching installations):</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>"Temporarily unavailable" - probably the cache cannot be found,
|
<li>"Temporarily unavailable" - probably the cache cannot be found,
|
||||||
but it may be repaired (then, "Ready to search" will be submitted).</li>
|
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>"Ready to search" - the cache can be found again.</li>
|
||||||
<li>"Archived" - the cache cannot be found and probably won't be
|
<li>"Archived" - the cache cannot be found and probably won't be
|
||||||
repaired.</li>
|
repaired.</li>
|
||||||
<li>"Locked" - the cache has been archived and can no longer be logged.</li>
|
<li>"Locked" - the cache has been archived and can no longer be logged.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Other types (used only by some Opencaching installations):</p>
|
<p>Other types (used only by some Opencaching installations):</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>"Needs maintenance" - a user states that the cache is
|
<li>"Needs maintenance" - a user states that the cache is
|
||||||
in need of maintenance.</li>
|
in need of maintenance.</li>
|
||||||
<li>"Maintenance performed" - the cache owner states that he
|
<li>"Maintenance performed" - the cache owner states that he
|
||||||
had performed the maintenance.</li>
|
had performed the maintenance.</li>
|
||||||
<li>"Moved" - the cache has been moved to a different location.</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
|
<li>"OC Team comment" - a comment made by the official OC Team
|
||||||
member.</li>
|
member.</li>
|
||||||
<li><i>(to be continued)</i> - this list MAY expand in time!
|
<li><i>(to be continued)</i> - this list MAY expand in time!
|
||||||
Your application should accept unknown log types (you may
|
Your application should accept unknown log types (you may
|
||||||
treat them as "Comment"s).</li>
|
treat them as "Comment"s).</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>oc_team_entry</b> - <b>true</b> if the log entry has been made by an
|
<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
|
official OC team member and marked as administrative log; <b>false</b> if it has
|
||||||
not been marked.</p>
|
not been marked.</p>
|
||||||
<p>Note: <b>false</b> does NOT mean that it is no administrative log,
|
<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>
|
because this flag can be missing for (mostly old) admin logs.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>was_recommended</b> - <b>true</b>, if the author included his recommendation
|
<p><b>was_recommended</b> - <b>true</b>, if the author included his recommendation
|
||||||
in this log entry,</p>
|
in this log entry,</p>
|
||||||
</li>
|
</li>
|
||||||
<li><b>comment</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>, text entered
|
<li><b>comment</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>, text entered
|
||||||
with the log entry,</li>
|
with the log entry,</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>images</b> - list of dictionaries, each dictionary represents one
|
<p><b>images</b> - list of dictionaries, each dictionary represents one
|
||||||
image saved along with the log; each dictionary has the following
|
image saved along with the log; each dictionary has the following
|
||||||
structure:</p>
|
structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>uuid</b> - UUID of the image,</li>
|
<li><b>uuid</b> - UUID of the image,</li>
|
||||||
<li><b>url</b> - URL 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>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>caption</b> - plain-text string, caption of the image,</li>
|
||||||
<li><b>is_spoiler</b> - boolean, if <b>true</b> then the image is
|
<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
|
a spoiler image and should not be displayed to the user unless
|
||||||
the user explicitly asks for it.</li>
|
the user explicitly asks for it.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>internal_id</b> - undocumented, you <u>should not</u> use
|
<p><b>internal_id</b> - undocumented, you <u>should not</u> use
|
||||||
this unless you really know you need to. Internal IDs are
|
this unless you really know you need to. Internal IDs are
|
||||||
<b>not</b> unique across various OKAPI installations.
|
<b>not</b> unique across various OKAPI installations.
|
||||||
Try to use UUIDs instead.</p>
|
Try to use UUIDs instead.</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>Note, that some fields can change in time (users can edit/delete
|
<p>Note, that some fields can change in time (users can edit/delete
|
||||||
their log entries).</p>
|
their log entries).</p>
|
||||||
|
|
||||||
<p>If given log entry does not exist, the method will
|
<p>If given log entry does not exist, the method will
|
||||||
respond with an HTTP 400 error.</p>
|
respond with an HTTP 400 error.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -15,58 +15,69 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$cache_code = $request->get_parameter('cache_code');
|
$cache_code = $request->get_parameter('cache_code');
|
||||||
if (!$cache_code) throw new ParamMissing('cache_code');
|
if (!$cache_code) throw new ParamMissing('cache_code');
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields) $fields = "uuid|date|user|type|comment";
|
if (!$fields) $fields = "uuid|date|user|type|comment";
|
||||||
|
|
||||||
$offset = $request->get_parameter('offset');
|
$offset = $request->get_parameter('offset');
|
||||||
if (!$offset) $offset = "0";
|
if (!$offset) $offset = "0";
|
||||||
if ((((int)$offset) != $offset) || ((int)$offset) < 0)
|
if ((((int)$offset) != $offset) || ((int)$offset) < 0)
|
||||||
throw new InvalidParam('offset', "Expecting non-negative integer.");
|
throw new InvalidParam('offset', "Expecting non-negative integer.");
|
||||||
$limit = $request->get_parameter('limit');
|
$limit = $request->get_parameter('limit');
|
||||||
if (!$limit) $limit = "none";
|
if (!$limit) $limit = "none";
|
||||||
if ($limit == "none") $limit = "999999999";
|
if ($limit == "none") $limit = "999999999";
|
||||||
if ((((int)$limit) != $limit) || ((int)$limit) < 0)
|
if ((((int)$limit) != $limit) || ((int)$limit) < 0)
|
||||||
throw new InvalidParam('limit', "Expecting non-negative integer or 'none'.");
|
throw new InvalidParam('limit', "Expecting non-negative integer or 'none'.");
|
||||||
|
|
||||||
# Check if code exists and retrieve cache ID (this will throw
|
# Check if code exists and retrieve cache ID (this will throw
|
||||||
# a proper exception on invalid code).
|
# a proper exception on invalid code).
|
||||||
|
|
||||||
$cache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
$cache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||||
$request->consumer, null, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
$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("
|
$log_uuids = Db::select_column("
|
||||||
select uuid
|
select uuid
|
||||||
from cache_logs
|
from cache_logs
|
||||||
where
|
where
|
||||||
cache_id = '".mysql_real_escape_string($cache['internal_id'])."'
|
cache_id = '".mysql_real_escape_string($cache['internal_id'])."'
|
||||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||||
order by date desc
|
order by date desc
|
||||||
limit $offset, $limit
|
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(
|
$internal_request = new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('log_uuids' => implode("|", $log_uuids),
|
$request->consumer, $request->token, array('log_uuids' => implode("|", $log_uuids),
|
||||||
'fields' => $fields));
|
'fields' => $fields));
|
||||||
$internal_request->skip_limits = true;
|
$internal_request->skip_limits = true;
|
||||||
$logs = OkapiServiceRunner::call('services/logs/entries', $internal_request);
|
$logs = OkapiServiceRunner::call('services/logs/entries', $internal_request);
|
||||||
$results = array();
|
$results = array();
|
||||||
foreach ($log_uuids as $log_uuid)
|
foreach ($log_uuids as $log_uuid)
|
||||||
$results[] = $logs[$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>
|
<xml>
|
||||||
<brief>Retrieve all log entries for the specified geocache</brief>
|
<brief>Retrieve all log entries for the specified geocache</brief>
|
||||||
<issue-id>41</issue-id>
|
<issue-id>41</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Retrieve the log entries for the specified geocache. Use the offset and
|
<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
|
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>
|
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>
|
<p>Log entries are ordered by a descending date of the entry.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='cache_code'>
|
<req name='cache_code'>
|
||||||
<p>Code of the geocache.</p>
|
<p>Code of the geocache.</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='fields' default='uuid|date|user|type|comment'>
|
<opt name='fields' default='uuid|date|user|type|comment'>
|
||||||
<p>Same as in the services/logs/entry method. Pipe-separated list
|
<p>Same as in the services/logs/entry method. Pipe-separated list
|
||||||
of field names which you are interested with.
|
of field names which you are interested with.
|
||||||
See services/logs/entry method for a list of available values.</p>
|
See services/logs/entry method for a list of available values.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='offset' default='0'>
|
<opt name='offset' default='0'>
|
||||||
<p>Number of entries to skip at the beginning. Use this along the <b>limit</b> parameter
|
<p>Number of entries to skip at the beginning. Use this along the <b>limit</b> parameter
|
||||||
for pagination.</p>
|
for pagination.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='limit' default='none'>
|
<opt name='limit' default='none'>
|
||||||
<p>Maximum number of entries to return or <b>none</b>
|
<p>Maximum number of entries to return or <b>none</b>
|
||||||
if you want all the entries.</p>
|
if you want all the entries.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A list of log entries, ordered by date. Each log entry is a dictionary of a format
|
<p>A list of log entries, ordered by date. Each log entry is a dictionary of a format
|
||||||
described in the "entry" method.</p>
|
described in the "entry" method.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,110 +1,110 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Submit a log entry</brief>
|
<brief>Submit a log entry</brief>
|
||||||
<issue-id>42</issue-id>
|
<issue-id>42</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Submit a log entry for the geocache. Please note, that you won't be
|
<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>
|
able to use this method until you learn to handle OAuth.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='cache_code'>
|
<req name='cache_code'>
|
||||||
<p>Code of the geocache.</p>
|
<p>Code of the geocache.</p>
|
||||||
</req>
|
</req>
|
||||||
<req name='logtype'>
|
<req name='logtype'>
|
||||||
<p>Type of an entry. This should be one of:</p>
|
<p>Type of an entry. This should be one of:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<i>Will attend</i>, <i>Attended</i> or <i>Comment</i> for Event caches;
|
<i>Will attend</i>, <i>Attended</i> or <i>Comment</i> for Event caches;
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<i>Found it</i>, <i>Didn't find it</i> or <i>Comment</i> for all other
|
<i>Found it</i>, <i>Didn't find it</i> or <i>Comment</i> for all other
|
||||||
cache types.
|
cache types.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</req>
|
</req>
|
||||||
<opt name='comment'>
|
<opt name='comment'>
|
||||||
<p>Text to be submitted with the log entry.</p>
|
<p>Text to be submitted with the log entry.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='comment_format' default='auto'>
|
<opt name='comment_format' default='auto'>
|
||||||
<p>Indicates the format of your <b>comment</b>. Three values allowed:
|
<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>
|
<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
|
use the <b>auto</b> option, because its exact behavior is unspecified
|
||||||
and may depend on the installation
|
and may depend on the installation
|
||||||
(<a href='https://code.google.com/p/opencaching-api/issues/detail?id=124'>more info</a>).</p>
|
(<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
|
<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
|
and may change in the future. For future-compatibility, you should use only
|
||||||
basic formatting tags.</p>
|
basic formatting tags.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='when'>
|
<opt name='when'>
|
||||||
<p>A date and time string. This should be in ISO 8601 format (currently any
|
<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>
|
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,
|
function also will do, but most of them don't handle time zones properly,
|
||||||
try to use ISO 8601!).</p>
|
try to use ISO 8601!).</p>
|
||||||
<p>Indicates when the cache was found. If given, the log will be published
|
<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
|
with the given date and time. If not, log will be published using the current
|
||||||
date and time.</p>
|
date and time.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='password'>
|
<opt name='password'>
|
||||||
<p>Some caches require a password in order to submit a "Found it" log entry.
|
<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
|
You may check if this cache requires password with <b>req_passwd</b> field
|
||||||
of the services/caches/geocache method.</p>
|
of the services/caches/geocache method.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='langpref' default='en'>
|
<opt name='langpref' default='en'>
|
||||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
<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>
|
order of preference in which language will be chosen for error messages.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='on_duplicate' default='silent_success'>
|
<opt name='on_duplicate' default='silent_success'>
|
||||||
<p>How should OKAPI react when you are trying to submit a duplicate entry?
|
<p>How should OKAPI react when you are trying to submit a duplicate entry?
|
||||||
One of the following values:</p>
|
One of the following values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>silent_success</b> - try to respond with success=true, but don't
|
<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>
|
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>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
|
<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
|
fail in some cases, i.e. when you're trying to submit a "Found it" entry for an
|
||||||
already found cache).</li>
|
already found cache).</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Note, that duplicate detection may take the <b>when</b> parameter into account.
|
<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
|
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>
|
have to supply the "when" parameter if you want duplicate detection to work.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='rating'>
|
<opt name='rating'>
|
||||||
<p>An integer in range between 1 and 5 - user's optional rating of a found cache.</p>
|
<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>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: 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
|
<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
|
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>
|
successfully, but rating will be ignored).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='recommend' default='false'>
|
<opt name='recommend' default='false'>
|
||||||
<p>Set to <b>true</b> if the user wants to recommend this cache.</p>
|
<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
|
<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
|
use this argument. However, some installations do not support recommending
|
||||||
event caches (if you include a recommendation, the log entry will be posted
|
event caches (if you include a recommendation, the log entry will be posted
|
||||||
successfully, but the recommendation will be <b>ignored</b>).</p>
|
successfully, but the recommendation will be <b>ignored</b>).</p>
|
||||||
<p>Recommending may only succeed when the user meets certain criteria
|
<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
|
set on him by the OC site. If criteria are not met, the request will
|
||||||
end with user error (HTTP 200, success=false).</p>
|
end with user error (HTTP 200, success=false).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='needs_maintenance' default='false'>
|
<opt name='needs_maintenance' default='false'>
|
||||||
<p>Set to <b>true</b> if the user thinks that the cache needs some special attension
|
<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>
|
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
|
<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
|
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
|
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
|
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>
|
<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
|
<p>Note: Currently, this is not allowed for Event Caches (you will get a HTTP 200
|
||||||
"user friendly" response).</p>
|
"user friendly" response).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>success</b> - true, if the log entry was submitted successfully,</li>
|
<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
|
<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>
|
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>
|
<li><b>log_uuid</b> - ID of the newly created log entry, <b>or null</b>
|
||||||
in case of an error.</li>
|
in case of an error.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -15,62 +15,62 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$user_uuid = $request->get_parameter('user_uuid');
|
$user_uuid = $request->get_parameter('user_uuid');
|
||||||
if (!$user_uuid) throw new ParamMissing('user_uuid');
|
if (!$user_uuid) throw new ParamMissing('user_uuid');
|
||||||
$limit = $request->get_parameter('limit');
|
$limit = $request->get_parameter('limit');
|
||||||
if (!$limit) $limit = "20";
|
if (!$limit) $limit = "20";
|
||||||
if (!is_numeric($limit))
|
if (!is_numeric($limit))
|
||||||
throw new InvalidParam('limit', "'$limit'");
|
throw new InvalidParam('limit', "'$limit'");
|
||||||
$limit = intval($limit);
|
$limit = intval($limit);
|
||||||
if (($limit < 1) || ($limit > 1000))
|
if (($limit < 1) || ($limit > 1000))
|
||||||
throw new InvalidParam('limit', "Has to be in range 1..1000.");
|
throw new InvalidParam('limit', "Has to be in range 1..1000.");
|
||||||
$offset = $request->get_parameter('offset');
|
$offset = $request->get_parameter('offset');
|
||||||
if (!$offset) $offset = "0";
|
if (!$offset) $offset = "0";
|
||||||
if (!is_numeric($offset))
|
if (!is_numeric($offset))
|
||||||
throw new InvalidParam('offset', "'$offset'");
|
throw new InvalidParam('offset', "'$offset'");
|
||||||
$offset = intval($offset);
|
$offset = intval($offset);
|
||||||
if ($offset < 0)
|
if ($offset < 0)
|
||||||
throw new InvalidParam('offset', "'$offset'");
|
throw new InvalidParam('offset', "'$offset'");
|
||||||
|
|
||||||
# Check if user exists and retrieve user's ID (this will throw
|
# Check if user exists and retrieve user's ID (this will throw
|
||||||
# a proper exception on invalid UUID).
|
# a proper exception on invalid UUID).
|
||||||
$user = OkapiServiceRunner::call('services/users/user', new OkapiInternalRequest(
|
$user = OkapiServiceRunner::call('services/users/user', new OkapiInternalRequest(
|
||||||
$request->consumer, null, array('user_uuid' => $user_uuid, 'fields' => 'internal_id')));
|
$request->consumer, null, array('user_uuid' => $user_uuid, 'fields' => 'internal_id')));
|
||||||
|
|
||||||
# User exists. Retrieving logs.
|
# User exists. Retrieving logs.
|
||||||
|
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select cl.id, cl.uuid, cl.type, unix_timestamp(cl.date) as date, cl.text,
|
select cl.id, cl.uuid, cl.type, unix_timestamp(cl.date) as date, cl.text,
|
||||||
c.wp_oc as cache_code
|
c.wp_oc as cache_code
|
||||||
from cache_logs cl, caches c
|
from cache_logs cl, caches c
|
||||||
where
|
where
|
||||||
cl.user_id = '".mysql_real_escape_string($user['internal_id'])."'
|
cl.user_id = '".mysql_real_escape_string($user['internal_id'])."'
|
||||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
||||||
and c.status in (1,2,3)
|
and c.status in (1,2,3)
|
||||||
and cl.cache_id = c.cache_id
|
and cl.cache_id = c.cache_id
|
||||||
order by cl.date desc
|
order by cl.date desc
|
||||||
limit $offset, $limit
|
limit $offset, $limit
|
||||||
");
|
");
|
||||||
$results = array();
|
$results = array();
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
{
|
{
|
||||||
$results[] = array(
|
$results[] = array(
|
||||||
'uuid' => $row['uuid'],
|
'uuid' => $row['uuid'],
|
||||||
'date' => date('c', $row['date']),
|
'date' => date('c', $row['date']),
|
||||||
'cache_code' => $row['cache_code'],
|
'cache_code' => $row['cache_code'],
|
||||||
'type' => Okapi::logtypeid2name($row['type']),
|
'type' => Okapi::logtypeid2name($row['type']),
|
||||||
'comment' => $row['text']
|
'comment' => $row['text']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Okapi::formatted_response($request, $results);
|
return Okapi::formatted_response($request, $results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,45 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve log entries of a specified user</brief>
|
<brief>Retrieve log entries of a specified user</brief>
|
||||||
<issue-id>80</issue-id>
|
<issue-id>80</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Retrieve log entries of a specified user.</p>
|
<p>Retrieve log entries of a specified user.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='user_uuid'>
|
<req name='user_uuid'>
|
||||||
<p>ID of the user. (Use services/users/by_username to get it.)</p>
|
<p>ID of the user. (Use services/users/by_username to get it.)</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='limit' default='20'>
|
<opt name='limit' default='20'>
|
||||||
<p>Integer N. If given, no more than N logs will be returned (the most recent ones).
|
<p>Integer N. If given, no more than N logs will be returned (the most recent ones).
|
||||||
Maximum allowed value is 1000.</p>
|
Maximum allowed value is 1000.</p>
|
||||||
<p>Note: Some users have thousands of log entries!</p>
|
<p>Note: Some users have thousands of log entries!</p>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='offset' default='0'>
|
<opt name='offset' default='0'>
|
||||||
<p>Combined with the <b>limit</b> argument, this gives you an abbility to get
|
<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>
|
<b>all</b> log entries of the user (with multiple requests).</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>Log entries. A dictionary of the following format:</p>
|
<p>A list of log entries, ordered by descending date. Each entry is a
|
||||||
<ul>
|
dictionary of the following format:</p>
|
||||||
<li><b>uuid</b> - ID of the log entry,</li>
|
|
||||||
<li>
|
<ul>
|
||||||
<p><b>date</b> - date and time (ISO 8601) when the log entry was submitted.</p>
|
<li><b>uuid</b> - ID of the log entry,</li>
|
||||||
<p>Please note that log entries often contain dates only (with the times
|
<li>
|
||||||
truncated to midnight, as in the local timezone). In such cases, you may
|
<p><b>date</b> - date and time (ISO 8601) when the log entry was submitted.</p>
|
||||||
want to avoid displaying the time. You may assume that if the <b>date</b>
|
<p>Please note that log entries often contain dates only (with the times
|
||||||
value contains the "00:00:00" string, then it is date-only.</p>
|
truncated to midnight, as in the local timezone). In such cases, you may
|
||||||
</li>
|
want to avoid displaying the time. You may assume that if the <b>date</b>
|
||||||
<li><b>cache_code</b> - code of the geocache,</li>
|
value contains the "00:00:00" string, then it is date-only.</p>
|
||||||
<li>
|
</li>
|
||||||
<p><b>type</b> - string; log type. This could be <b>pretty much
|
<li><b>cache_code</b> - code of the geocache,</li>
|
||||||
everything</b>, but there are some primary types (see logs/entry
|
<li>
|
||||||
method for more info).</p>
|
<p><b>type</b> - string; log type. This could be <b>pretty much
|
||||||
</li>
|
everything</b>, but there are some primary types (see logs/entry
|
||||||
<li><b>comment</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>, text entered
|
method for more info).</p>
|
||||||
with the log entry.</li>
|
</li>
|
||||||
</ul>
|
<li>
|
||||||
</returns>
|
<b>comment</b> - <a href='%OKAPI:docurl:html%'>HTML string</a>, text entered
|
||||||
|
with the log entry.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -10,28 +10,28 @@ use okapi\InvalidParam;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 3,
|
'min_auth_level' => 3,
|
||||||
'token_type' => 'request'
|
'token_type' => 'request'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$verifier = $request->get_parameter('oauth_verifier');
|
$verifier = $request->get_parameter('oauth_verifier');
|
||||||
if (!$verifier)
|
if (!$verifier)
|
||||||
{
|
{
|
||||||
# We require the 1.0a flow (throw an error when there is no oauth_verifier).
|
# We require the 1.0a flow (throw an error when there is no oauth_verifier).
|
||||||
throw new ParamMissing("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 = new OkapiHttpResponse();
|
||||||
$response->content_type = "text/plain; charset=utf-8";
|
$response->content_type = "text/plain; charset=utf-8";
|
||||||
$response->body = $new_token;
|
$response->body = $new_token;
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Exchange authorized Request Token for an Access Token</brief>
|
<brief>Exchange authorized Request Token for an Access Token</brief>
|
||||||
<issue-id>21</issue-id>
|
<issue-id>21</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Exchange authorized Request Token for an Access Token.
|
<p>Exchange authorized Request Token for an Access Token.
|
||||||
Access Token can be used to access resources of a user who
|
Access Token can be used to access resources of a user who
|
||||||
authorized the Request Token.</p>
|
authorized the Request Token.</p>
|
||||||
<p>Standard OAuth "Consumer & Request Token" Authorization arguments
|
<p>Standard OAuth "Consumer & Request Token" Authorization arguments
|
||||||
are required.</p>
|
are required.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='oauth_verifier'>
|
<req name='oauth_verifier'>
|
||||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||||
</req>
|
</req>
|
||||||
<returns>
|
<returns>
|
||||||
<p>Standard OAuth 1.0a Token response - a string in a form-encoded format:</p>
|
<p>Standard OAuth 1.0a Token response - a string in a form-encoded format:</p>
|
||||||
<pre>oauth_token=...&oauth_token_secret=...</pre>
|
<pre>oauth_token=...&oauth_token_secret=...</pre>
|
||||||
<p>You <b>must</b> be prepared that there might be more parameters returned
|
<p>You <b>must</b> be prepared that there might be more parameters returned
|
||||||
in the future (you should ignore them gracefully).</p>
|
in the future (you should ignore them gracefully).</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
|
|||||||
@@ -11,31 +11,31 @@ use okapi\InvalidParam;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 0
|
'min_auth_level' => 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$token_key = $request->get_parameter('oauth_token');
|
$token_key = $request->get_parameter('oauth_token');
|
||||||
if (!$token_key)
|
if (!$token_key)
|
||||||
throw new ParamMissing("oauth_token");
|
throw new ParamMissing("oauth_token");
|
||||||
$langpref = $request->get_parameter('langpref');
|
$langpref = $request->get_parameter('langpref');
|
||||||
$interactivity = $request->get_parameter('interactivity');
|
$interactivity = $request->get_parameter('interactivity');
|
||||||
if (!$interactivity) $interactivity = 'minimal';
|
if (!$interactivity) $interactivity = 'minimal';
|
||||||
if (!in_array($interactivity, array('minimal', 'confirm_user')))
|
if (!in_array($interactivity, array('minimal', 'confirm_user')))
|
||||||
throw new InvalidParam('interactivity', $interactivity);
|
throw new InvalidParam('interactivity', $interactivity);
|
||||||
|
|
||||||
# Redirect to the "apps" folder. This is done there (not here)
|
# Redirect to the "apps" folder. This is done there (not here)
|
||||||
# because: 1) we don't want any cookie or session-handling
|
# because: 1) we don't want any cookie or session-handling
|
||||||
# done in the "services" folder. 2) "services" don't display
|
# done in the "services" folder. 2) "services" don't display
|
||||||
# any interactive webpages, they just return the result.
|
# any interactive webpages, they just return the result.
|
||||||
|
|
||||||
return new OkapiRedirectResponse(Settings::get('SITE_URL')."okapi/apps/authorize".
|
return new OkapiRedirectResponse(Settings::get('SITE_URL')."okapi/apps/authorize".
|
||||||
"?oauth_token=".$token_key.(($langpref != null) ? "&langpref=".$langpref : "").
|
"?oauth_token=".$token_key.(($langpref != null) ? "&langpref=".$langpref : "").
|
||||||
"&interactivity=".$interactivity);
|
"&interactivity=".$interactivity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Authorize the Request Token</brief>
|
<brief>Authorize the Request Token</brief>
|
||||||
<issue-id>22</issue-id>
|
<issue-id>22</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Unlike other methods, the <b>authorize</b> method is to be executed
|
<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
|
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>
|
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>
|
<p>Once the User is redirected to this URL, several things will happen:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>If he's not already logged in, he will be asked to do so.</li>
|
<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
|
<li>OKAPI will check if the User haven't previously granted your
|
||||||
application access to his Opencaching account.</li>
|
application access to his Opencaching account.</li>
|
||||||
<li>If User did not previously authorize your application, OKAPI
|
<li>If User did not previously authorize your application, OKAPI
|
||||||
will display an "Authorization Request" form to the User. User
|
will display an "Authorization Request" form to the User. User
|
||||||
will be presented with a choice to allow or not to allow your
|
will be presented with a choice to allow or not to allow your
|
||||||
application access to his account.</li>
|
application access to his account.</li>
|
||||||
<li>If the User clicks one of these two options ("allow" or "don't allow"),
|
<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
|
he's browser will be redirected to the <b>callback_url</b> you defined
|
||||||
while getting your Request Token.
|
while getting your Request Token.
|
||||||
If you did not provide a callback (in other word, provided "oob"),
|
If you did not provide a callback (in other word, provided "oob"),
|
||||||
user will be redirected to a default "authorized" page, where he
|
user will be redirected to a default "authorized" page, where he
|
||||||
will be presented with an oauth_verifier (user will know it
|
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>
|
by name of a <b>PIN code</b>) and asked to type it into your application.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='oauth_token'>
|
<req name='oauth_token'>
|
||||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||||
</req>
|
</req>
|
||||||
<opt name='interactivity' default='minimal'>
|
<opt name='interactivity' default='minimal'>
|
||||||
<p>Currently, one of the following values:</p>
|
<p>Currently, one of the following values:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>minimal</b> - OKAPI will use as little interactivity as it can.
|
<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
|
It will assume that currently logged in user is the user which you
|
||||||
want to authorize. If the user has already authorized your application,
|
want to authorize. If the user has already authorized your application,
|
||||||
he will not be asked to do this again.</li>
|
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
|
<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
|
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
|
offer to authorize a different user (e.g. by automatically logging out
|
||||||
the user who is currently logged in).</li>
|
the user who is currently logged in).</li>
|
||||||
</ul>
|
</ul>
|
||||||
</opt>
|
</opt>
|
||||||
<opt name='langpref'>
|
<opt name='langpref'>
|
||||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
<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>
|
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
|
<p>By default, OKAPI will display the page in the primary native language of local
|
||||||
Opencaching installation.</p>
|
Opencaching installation.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<returns>
|
<returns>
|
||||||
<p>Technically, an HTTP 302 Redirect - it will direct user's browser to the OKAPI apps
|
<p>Technically, an HTTP 302 Redirect - it will direct user's browser to the OKAPI apps
|
||||||
authorization page.</p>
|
authorization page.</p>
|
||||||
<p>Whether with callback_url or with a manual user entry - you will get
|
<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
|
your <b>oauth_verifier</b>, which allows you to continue the 3-legged
|
||||||
authentication dance.</p>
|
authentication dance.</p>
|
||||||
<p>If you used <b>callback_url</b>, you should wait for an HTTP GET request,
|
<p>If you used <b>callback_url</b>, you should wait for an HTTP GET request,
|
||||||
with one additional GET parameter appended:</p>
|
with one additional GET parameter appended:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>oauth_token</b> - the Request Token that has been just authorized,</li>
|
<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>
|
<li><b>oauth_verifier</b> - the PIN code required to get an Access Token.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>OR, in case when user denied the request:</p>
|
<p>OR, in case when user denied the request:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>oauth_token</b> - the Request Token,</li>
|
<li><b>oauth_token</b> - the Request Token,</li>
|
||||||
<li><b>error</b> - codename of an error - <b>access_denied</b>.</li>
|
<li><b>error</b> - codename of an error - <b>access_denied</b>.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
|
|||||||
@@ -10,27 +10,27 @@ use okapi\InvalidParam;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 2
|
'min_auth_level' => 2
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$callback = $request->get_parameter('oauth_callback');
|
$callback = $request->get_parameter('oauth_callback');
|
||||||
if (!$callback)
|
if (!$callback)
|
||||||
{
|
{
|
||||||
# We require the 1.0a flow (throw an error when there is no oauth_callback).
|
# We require the 1.0a flow (throw an error when there is no oauth_callback).
|
||||||
throw new ParamMissing("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 = new OkapiHttpResponse();
|
||||||
$response->content_type = "text/plain; charset=utf-8";
|
$response->content_type = "text/plain; charset=utf-8";
|
||||||
$response->body = $new_token."&oauth_callback_confirmed=true";
|
$response->body = $new_token."&oauth_callback_confirmed=true";
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get a new unauthorized OAuth Request Token</brief>
|
<brief>Get a new unauthorized OAuth Request Token</brief>
|
||||||
<issue-id>23</issue-id>
|
<issue-id>23</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Get a new unauthorized OAuth Request Token. This token is bound to
|
<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
|
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
|
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>
|
the user, then it has to be exchanged for an Access Token.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='oauth_callback'>
|
<req name='oauth_callback'>
|
||||||
<p>URL which you want a User to be redirected to after a
|
<p>URL which you want a User to be redirected to after a
|
||||||
successful Request Token Authorization (see "authorize" method).
|
successful Request Token Authorization (see "authorize" method).
|
||||||
If the client is unable to receive callbacks, the parameter
|
If the client is unable to receive callbacks, the parameter
|
||||||
must be set to "oob", OKAPI will provide a user with a
|
must be set to "oob", OKAPI will provide a user with a
|
||||||
PIN code (oauth_verifier) in this case.</p>
|
PIN code (oauth_verifier) in this case.</p>
|
||||||
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
Consult <a href='http://oauth.net/documentation/spec/'>OAuth documentation</a> for details.
|
||||||
</req>
|
</req>
|
||||||
<returns>
|
<returns>
|
||||||
<p>Standard OAuth 1.0a Token response - a string in a form-encoded format:</p>
|
<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>
|
<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
|
<p>You <b>must</b> be prepared that there might be more parameters returned
|
||||||
in the future (you should ignore them gracefully).</p>
|
in the future (you should ignore them gracefully).</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
|
|||||||
@@ -17,37 +17,37 @@ use okapi\services\replicate\ReplicateCommon;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
require_once('replicate_common.inc.php');
|
require_once('replicate_common.inc.php');
|
||||||
|
|
||||||
$since = $request->get_parameter('since');
|
$since = $request->get_parameter('since');
|
||||||
if ($since === null) throw new ParamMissing('since');
|
if ($since === null) throw new ParamMissing('since');
|
||||||
if ((int)$since != $since) throw new InvalidParam('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))
|
if (!ReplicateCommon::check_since_param($since))
|
||||||
throw new BadRequest("The 'since' parameter is too old. You must update your database more frequently.");
|
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);
|
list($from, $to) = ReplicateCommon::select_best_chunk($since);
|
||||||
$clog_entries = ReplicateCommon::get_chunk($from, $to);
|
$clog_entries = ReplicateCommon::get_chunk($from, $to);
|
||||||
|
|
||||||
$result = array(
|
$result = array(
|
||||||
'changelog' => &$clog_entries,
|
'changelog' => &$clog_entries,
|
||||||
'revision' => $to + 0,
|
'revision' => $to + 0,
|
||||||
'more' => $to < ReplicateCommon::get_revision(),
|
'more' => $to < ReplicateCommon::get_revision(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,133 +1,140 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get the list of changes for your database</brief>
|
<brief>Get the list of changes for your database</brief>
|
||||||
<issue-id>109</issue-id>
|
<issue-id>109</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p><b>Beta status.</b> Get the list of changes to be replayed on your own copy
|
<p>Get the list of changes to be <u>replayed on your own copy
|
||||||
of Opencaching database. Use this method periodically (ex. once per hour) to
|
of Opencaching database</u>. Use this method periodically (e.g. every 5 minutes) to
|
||||||
keep your database in sync with ours.</p>
|
keep your database in sync with ours.</p>
|
||||||
|
|
||||||
<p>For some applications it might be desireable to have a quick access to the entire
|
<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
|
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
|
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
|
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>
|
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>
|
<p>A couple of things for you to remember:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>You <b>must</b> update your database frequently for this method to work.
|
<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>
|
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 every
|
|
||||||
5 minutes. This won't do you any good, since we update the changelog only once
|
<li>You <b>should not</b> update your database more frequently than once per
|
||||||
every 5 minutes anyway.</li>
|
5 minutes. This could kill our servers, and it wouldn't do you any good, since
|
||||||
</ul>
|
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
|
<p>Let's assume that you already have a copy of OKAPI database, but it's
|
||||||
your copy to the most current state.</p>
|
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
|
<p>Changelog is the list of all changes which appeared in the OKAPI database
|
||||||
list of changes and to replay them on your copy of our database. After you do
|
since the last time you downloaded it. What you have to do is to download this
|
||||||
this, your database is up-to-date.</p>
|
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>
|
<p>We use <b>revision</b> numbers to keep track of all the versions of the
|
||||||
number along with it. You must keep this number carefully, because you need
|
database. Every time we update a database, the <b>revision</b> is increased.
|
||||||
it in order for us to generate a proper changelog for you next time you ask
|
You will also receive this number every time you fetch a changelog or a fulldump
|
||||||
for it.</p>
|
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
|
||||||
<p>Example. This is a valid list of requests you should issue and their
|
for it!</p>
|
||||||
responses:</p>
|
|
||||||
<ul>
|
<p><b>Example.</b> This is a valid list of requests you should issue and their
|
||||||
<li><b>fulldump</b> - you receive a fulldump of our database with the
|
responses:</p>
|
||||||
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
|
<ul>
|
||||||
recorded since revision 238004. It responds with the list of changes and the
|
<li><b>fulldump</b> - you receive a fulldump of our database with the
|
||||||
new revision number 238017. You replay the changes on your database.</li>
|
revision number 238004. <b>You will call this method only once</b> (to
|
||||||
<li>You wait for some time between requesting the changelog again.</li>
|
initiate your copy of the database).</li>
|
||||||
<li><b>changelog</b>?since=238017 - etc.</li>
|
|
||||||
</ul>
|
<li><b>changelog</b>?since=238004 - OKAPI checks if there were any changes
|
||||||
</desc>
|
recorded since revision 238004. It responds with the list of changes and the
|
||||||
<req name='since'>
|
new revision number 238017. You replay the changes on your database.</li>
|
||||||
<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>
|
<li>You wait for some time between requesting the changelog again.</li>
|
||||||
|
|
||||||
<p>Old revisions are deleted, the <b>since</b> argument MUST referer to a revision no older
|
<li>Upon your next update, you'll ask for <b>changelog</b>?since=238017, etc.</li>
|
||||||
than 10 days. You will have to download a fulldump if you have an older copy
|
</ul>
|
||||||
(shame on you!).</p>
|
</desc>
|
||||||
</req>
|
<req name='since'>
|
||||||
<common-format-params/>
|
<p>Current revision of your database. This should be the same as the value
|
||||||
<returns>
|
of <b>revision</b> attribute, which you received with your previous update.</p>
|
||||||
<p>A dictionary of the following structure:</p>
|
|
||||||
<ul>
|
<p>Old revisions are deleted, the <b>since</b> argument MUST referer to a revision no older
|
||||||
<li>
|
than 10 days. You will have to download a fulldump if you have an older copy
|
||||||
<p><b>changelog</b> - a <b>list</b> of dictionaries. Each dictionary has the following structure:</p>
|
(shame on you!).</p>
|
||||||
<ul>
|
</req>
|
||||||
<li>
|
<common-format-params/>
|
||||||
<p><b>object_type</b> - string, object type to which the change refers to. One of the following values:</p>
|
<returns>
|
||||||
<ul>
|
<p>A dictionary of the following structure:</p>
|
||||||
<li><b>geocache</b> - this change refers to a geocache object,</li>
|
<ul>
|
||||||
<li><b>log_entry</b> - this change refers to a log entry.</li>
|
<li>
|
||||||
</ul>
|
<p><b>changelog</b> - a <b>list</b> of dictionaries. Each dictionary has the following structure:</p>
|
||||||
<p>More object types will come in the future. You should ignore all changelog
|
<ul>
|
||||||
entries with an unknown object_type.</p>
|
<li>
|
||||||
</li>
|
<p><b>object_type</b> - string, object type to which the change refers to. One of the following values:</p>
|
||||||
<li>
|
<ul>
|
||||||
<p><b>object_key</b> - a dictionary of fields which compose the primary key for the object.
|
<li><b>geocache</b> - this change refers to a geocache object,</li>
|
||||||
This will be the <b>code</b> field for the <b>geocache</b> object, and <b>uuid</b> field
|
<li><b>log_entry</b> - this change refers to a log entry.</li>
|
||||||
for the <b>log_entry</b> object.</p>
|
</ul>
|
||||||
</li>
|
<p>More object types will come in the future. You should ignore all changelog
|
||||||
<li>
|
entries with an unknown object_type.</p>
|
||||||
<p><b>change_type</b> - string, the type of the change. One of the following values:</p>
|
</li>
|
||||||
<ul>
|
<li>
|
||||||
<li><b>replace</b> - the object was inserted or updated. You should check if you
|
<p><b>object_key</b> - a dictionary of fields which compose the primary key for the object.
|
||||||
already have the object in your database. If you have it, you should update its
|
This will be the <b>code</b> field for the <b>geocache</b> object, and <b>uuid</b> field
|
||||||
fields accordingly. If you don't, you should create it.</li>
|
for the <b>log_entry</b> object.</p>
|
||||||
<li><b>delete</b> - the object was deleted. You should check if you already have
|
</li>
|
||||||
the object in your database. If you do, you should delete it.</li>
|
<li>
|
||||||
</ul>
|
<p><b>change_type</b> - string, the type of the change. One of the following values:</p>
|
||||||
</li>
|
<ul>
|
||||||
<li>
|
<li><b>replace</b> - the object was inserted or updated. You should check if you
|
||||||
<p><b>fields</b> - a dictionary of fields associated with the object (present only
|
already have the object in your database. If you have it, you should update its
|
||||||
if <b>change_type</b> equals <b>replace</b>).</p>
|
fields accordingly. If you don't, you should create it.</li>
|
||||||
<ul>
|
<li><b>delete</b> - the object was deleted. You should check if you already have
|
||||||
<li>For <b>geocache</b> objects, this might be any subset of fields described
|
the object in your database. If you do, you should delete it.</li>
|
||||||
in the services/caches/geocache method. Note that not all of these fields will
|
</ul>
|
||||||
be included here (i.e. latest_logs will not).</li>
|
</li>
|
||||||
<li>For <b>log_entry</b> objects, this might be any subset of fields described
|
<li>
|
||||||
in the services/logs/logs method, <b>plus</b> additional <b>cache_code</b> field,
|
<p><b>data</b> - a dictionary of fields associated with the object (present only
|
||||||
the code of the geocache to which the log entry refers to.</li>
|
if <b>change_type</b> equals <b>replace</b>).</p>
|
||||||
</ul>
|
<ul>
|
||||||
<p>In theory this dictionary should contain only these fields which actually changed.
|
<li>For <b>geocache</b> objects, this might be any subset of fields described
|
||||||
In truth, it MAY contain all the other fields too. This behavior may change in future.</p>
|
in the services/caches/geocache method. Note that not all of these fields will
|
||||||
</li>
|
be included here (i.e. latest_logs will not).</li>
|
||||||
</ul>
|
<li>For <b>log_entry</b> objects, this might be any subset of fields described
|
||||||
<p>You should iterate through this changelog sequentially. All the changes should be applied
|
in the services/logs/logs method, <b>plus</b> additional <b>cache_code</b> field,
|
||||||
in the same order as they were listed in the changelog. Single object may appear multiple times
|
the code of the geocache to which the log entry refers to.</li>
|
||||||
inside the changelog. Changelog will contain all the changes which occured since the time you
|
</ul>
|
||||||
specified in the <b>since</b> parameter and it MAY contain some more, which were submitted
|
<p>In theory this dictionary should contain only these fields which actually changed.
|
||||||
<b>before</b> this date (see below). The changes which are unnecessary MAY be skipped (ex. when
|
In truth, it MAY contain all the other fields too. This behavior may change in future.</p>
|
||||||
cache description changes multiple times, we may want to include only the last change).</p>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
<li>
|
<p>You should iterate through this changelog sequentially. All the changes should be applied
|
||||||
<p><b>revision</b> - this is the revision number which you should use in the <b>since</b> parameter
|
in the same order as they were listed in the changelog. Single object may appear multiple times
|
||||||
when you call this method next time.</p>
|
inside the changelog. Changelog will contain all the changes which occured since the time you
|
||||||
</li>
|
specified in the <b>since</b> parameter and it MAY contain some more, which were submitted
|
||||||
<li>
|
<b>before</b> this date (see below). The changes which are unnecessary MAY be skipped (ex. when
|
||||||
<p><b>more</b> - boolean. If <b>false</b>, then it means that the entire changelog had been
|
cache description changes multiple times, we may want to include only the last change).</p>
|
||||||
pulled. If <b>true</b>, then there are more items waiting to be pulled - you should rerun this
|
</li>
|
||||||
method again (with the value of <b>revision</b> inserted in the <b>since</b> parameter).</p>
|
<li>
|
||||||
<p>The changelog is usually tiny, but it also might be huge at times. It may even
|
<p><b>revision</b> - this is the revision number which you should use in the <b>since</b> parameter
|
||||||
contain all the caches in the database (i.e. if we decide to do some changes on all
|
when you call this method next time.</p>
|
||||||
caches in a bulk). This is the reason why we introduced the <b>more</b> attribute. It makes it
|
</li>
|
||||||
easier to parse the changelog sequentially.</p>
|
<li>
|
||||||
</li>
|
<p><b>more</b> - boolean. If <b>false</b>, then it means that the entire changelog had been
|
||||||
</ul>
|
pulled. If <b>true</b>, then there are more items waiting to be pulled - you should rerun this
|
||||||
<p>The response MAY contain changes recorded before the revision which you stated in your <b>since</b>
|
method again (with the value of <b>revision</b> inserted in the <b>since</b> parameter).</p>
|
||||||
parameter. This is due to caching. If we already have a response ready, that was produced for a
|
<p>The changelog is usually tiny, but it also might be huge at times. It may even
|
||||||
"since" parameter which was a little more in the past, we may want to return this cached copy,
|
contain all the caches in the database (i.e. if we decide to do some changes on all
|
||||||
instead of producing a new one. It will be faster for us, and you shouldn't even notice. We will
|
caches in a bulk). This is the reason why we introduced the <b>more</b> attribute. It makes it
|
||||||
still make sure to set the <b>revision</b> and <b>more</b> attributes in a correct way, which
|
easier to parse the changelog sequentially.</p>
|
||||||
in turn will make you query us again, if you need to.</p>
|
</li>
|
||||||
</returns>
|
</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>
|
</xml>
|
||||||
@@ -14,67 +14,67 @@ use okapi\BadRequest;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function count_calls($consumer_key, $days)
|
private static function count_calls($consumer_key, $days)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
Db::select_value("
|
Db::select_value("
|
||||||
select count(*)
|
select count(*)
|
||||||
from okapi_stats_temp
|
from okapi_stats_temp
|
||||||
where
|
where
|
||||||
consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
||||||
and service_name='services/replicate/fulldump'
|
and service_name='services/replicate/fulldump'
|
||||||
")
|
")
|
||||||
+
|
+
|
||||||
Db::select_value("
|
Db::select_value("
|
||||||
select sum(total_calls)
|
select sum(total_calls)
|
||||||
from okapi_stats_hourly
|
from okapi_stats_hourly
|
||||||
where
|
where
|
||||||
consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
||||||
and service_name='services/replicate/fulldump'
|
and service_name='services/replicate/fulldump'
|
||||||
and period_start > date_add(now(), interval -$days day)
|
and period_start > date_add(now(), interval -$days day)
|
||||||
limit 1
|
limit 1
|
||||||
")
|
")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
require_once('replicate_common.inc.php');
|
require_once('replicate_common.inc.php');
|
||||||
|
|
||||||
$data = Cache::get("last_fulldump");
|
$data = Cache::get("last_fulldump");
|
||||||
if ($data == null)
|
if ($data == null)
|
||||||
throw new BadRequest("No fulldump found. Try again later. If this doesn't help ".
|
throw new BadRequest("No fulldump found. Try again later. If this doesn't help ".
|
||||||
"contact site administrator and/or OKAPI developers.");
|
"contact site administrator and/or OKAPI developers.");
|
||||||
|
|
||||||
# Check consumer's quota
|
# Check consumer's quota
|
||||||
|
|
||||||
$please = $request->get_parameter('pleeaase');
|
$please = $request->get_parameter('pleeaase');
|
||||||
if ($please != 'true')
|
if ($please != 'true')
|
||||||
{
|
{
|
||||||
$not_good = 3 < self::count_calls($request->consumer->key, 30);
|
$not_good = 3 < self::count_calls($request->consumer->key, 30);
|
||||||
if ($not_good)
|
if ($not_good)
|
||||||
throw new BadRequest("Consumer's monthly quota exceeded. Try later or call with '&pleeaase=true'.");
|
throw new BadRequest("Consumer's monthly quota exceeded. Try later or call with '&pleeaase=true'.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$not_good = 5 < self::count_calls($request->consumer->key, 1);
|
$not_good = 5 < self::count_calls($request->consumer->key, 1);
|
||||||
if ($not_good)
|
if ($not_good)
|
||||||
throw new BadRequest("No more please. Seriously, dude...");
|
throw new BadRequest("No more please. Seriously, dude...");
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = new OkapiHttpResponse();
|
$response = new OkapiHttpResponse();
|
||||||
$response->content_type = $data['meta']['content_type'];
|
$response->content_type = $data['meta']['content_type'];
|
||||||
$response->content_disposition = 'attachment; filename="'.$data['meta']['public_filename'].'"';
|
$response->content_disposition = 'attachment; filename="'.$data['meta']['public_filename'].'"';
|
||||||
$response->stream_length = $data['meta']['compressed_size'];
|
$response->stream_length = $data['meta']['compressed_size'];
|
||||||
$response->body = fopen($data['meta']['filepath'], "rb");
|
$response->body = fopen($data['meta']['filepath'], "rb");
|
||||||
$response->allow_gzip = false;
|
$response->allow_gzip = false;
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,68 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Download OKAPI database snapshot</brief>
|
<brief>Download OKAPI database snapshot</brief>
|
||||||
<issue-id>110</issue-id>
|
<issue-id>110</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Download the latest snapshot of OKAPI database. You should call this method
|
<p>Download the latest snapshot of OKAPI database. You should call this method
|
||||||
only once.</p>
|
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>
|
|
||||||
|
|
||||||
<p><b>Important:</b> There is a remote possibility that this method MAY change in
|
<p>For some applications it might be desireable to have a quick access to the entire
|
||||||
a non-backward-compatible way or it might even get removed. We don't plan on doing
|
Opencaching database (instead of querying for specific portions of it). You may use
|
||||||
this, but we might be forced to (i.e. to prevent abuse).</p>
|
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
|
||||||
<p><b>Note:</b> The cache descriptions will be generated using the <b>attribution_append=static</b>
|
your first database copy, you will need to use the <b>fulldump</b> method.</p>
|
||||||
parameter (see the geocache method). Full attributions are not always suitable for replication,
|
|
||||||
since they may contain dates on some installations
|
<p>A couple of things for you to remember:</p>
|
||||||
(<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
|
<ul>
|
||||||
Licence (the Sign Up page).</p>
|
<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
|
||||||
<p>A couple of things for you to remember:</p>
|
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
|
||||||
<ul>
|
must use <b>your own server</b> for serving fulldump requests. (You don't
|
||||||
<li>Currently, this functionality is available <b>for developers only</b>,
|
have to use your server to relay changelog requests.)</li>
|
||||||
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.
|
<li>Fulldump is a copy of the entire database. We generate such copy once every couple of
|
||||||
If you want to enable such features for your users, you can do it, but you
|
days. This copy if intended for you to make a fresh start only. Later, you
|
||||||
must use <b>your own server</b> for data traffic (especially, fulldump requests).</li>
|
must use the <b>changelog</b> method to keep your data up-to-date.</li>
|
||||||
|
|
||||||
<li>Fulldump is a copy of the entire database. We generate such copy once every couple of
|
<li>Every time our database is extended (new fields or new object types), and you want to
|
||||||
days. This copy if intended for you to start only, later you must use the changelog to
|
make use of these new fields, you are of course allowed to download a fulldump copy again.</li>
|
||||||
keep it up-to-date.</li>
|
|
||||||
|
<li>There is no XMLMAP version of this file. JSON only.</li>
|
||||||
<li>Every time our database is extended (new fields or new object types), and you want to
|
</ul>
|
||||||
make use of these new fields, you are of course allowed to download a fulldump copy again.</li>
|
|
||||||
|
<p><b>Additional notes on data attribution:</b> Cache descriptions will be
|
||||||
<li>There is no XMLMAP version of this file.</li>
|
generated using the <b>attribution_append=static</b> parameter (see the
|
||||||
</ul>
|
geocache method). This is because the full attributions are not always suitable
|
||||||
</desc>
|
for replication, since they may contain dynamically changing dates on some
|
||||||
<returns>
|
installations (<a href='https://code.google.com/p/opencaching-api/issues/detail?id=178'>why?</a>).
|
||||||
<p>Archive with JSON-encoded files. File named <b>index.json</b> will contain a dictionary
|
To make sure that static attributions are enough, consult the local Data
|
||||||
of the following structure:</p>
|
Licence (the Sign Up page).</p>
|
||||||
<ul>
|
</desc>
|
||||||
<li><b>revision</b> - revision of the database snapshot contained in the archive,</li>
|
<returns>
|
||||||
<li><b>data_files</b> - list of filenames which contain the changelog entries for
|
<p>Compressed archive with JSON-encoded files. File named <b>index.json</b> will
|
||||||
you to parse. Each file contains a JSON-encoded list of changelog entries, in format
|
contain a dictionary of the following structure:</p>
|
||||||
described in the <b>changelog</b> method ("replace" only).</li>
|
|
||||||
<li><b>meta</b> - a dictionary of other meta data, not important.</li>
|
<ul>
|
||||||
</ul>
|
<li><b>revision</b> - revision of the database snapshot contained in the archive,</li>
|
||||||
<p>Note: We use TGZ or TBZ2 format to encode this archive:</p>
|
|
||||||
<ul>
|
<li><b>data_files</b> - list of filenames which contain the changelog entries for
|
||||||
<li><b>TGZ</b> archive (more commonly known as <b>.tar.gz</b> archive) is a TAR
|
you to parse. Each file contains a JSON-encoded list of changelog entries, in format
|
||||||
archive compressed with GZIP.</li>
|
described in the <b>changelog</b> method ("replace" only).</li>
|
||||||
<li><b>TBZ2</b> archive (more commonly known as <b>.tar.bz2</b> archive) is a TAR
|
|
||||||
archive compressed with BZIP2.</li>
|
<li><b>meta</b> - a dictionary of other meta data, not important.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>There are many tools available for handling these archives. In Linux, try "tar -xf filename".</p>
|
|
||||||
</returns>
|
<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>
|
</xml>
|
||||||
@@ -18,35 +18,35 @@ use okapi\services\replicate\ReplicateCommon;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
require_once('replicate_common.inc.php');
|
require_once('replicate_common.inc.php');
|
||||||
|
|
||||||
$result = array();
|
$result = array();
|
||||||
$result['changelog'] = array(
|
$result['changelog'] = array(
|
||||||
'min_since' => ReplicateCommon::get_min_since(),
|
'min_since' => ReplicateCommon::get_min_since(),
|
||||||
'revision' => ReplicateCommon::get_revision(),
|
'revision' => ReplicateCommon::get_revision(),
|
||||||
);
|
);
|
||||||
$dump = Cache::get("last_fulldump");
|
$dump = Cache::get("last_fulldump");
|
||||||
if ($dump)
|
if ($dump)
|
||||||
{
|
{
|
||||||
$result['latest_fulldump'] = array(
|
$result['latest_fulldump'] = array(
|
||||||
'revision' => $dump['revision'],
|
'revision' => $dump['revision'],
|
||||||
'generated_at' => $dump['meta']['generated_at'],
|
'generated_at' => $dump['meta']['generated_at'],
|
||||||
'size' => $dump['meta']['compressed_size'],
|
'size' => $dump['meta']['compressed_size'],
|
||||||
'size_uncompressed' => $dump['meta']['uncompressed_size'],
|
'size_uncompressed' => $dump['meta']['uncompressed_size'],
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$result['latest_fulldump'] = null;
|
$result['latest_fulldump'] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Get information on current changelog and fulldump state</brief>
|
<brief>Get information on current changelog and fulldump state</brief>
|
||||||
<issue-id>111</issue-id>
|
<issue-id>111</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p><b>Beta status.</b> Get information on current changelog and fulldump state.</p>
|
<p><b>Beta status.</b> Get information on current changelog and fulldump state.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of the following structure:</p>
|
<p>A dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p><b>changelog</b> - a dictionary of the following structure:</p>
|
<p><b>changelog</b> - a dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>min_since</b> - the lowest allowed value for the <b>since</b> attribute
|
<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>
|
(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
|
<li><b>revision</b> - the current revision of the database (the ID of the
|
||||||
newest changelog entry kept in our database),</li>
|
newest changelog entry kept in our database),</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>latest_fulldump</b> - a dictionary of the following structure:</p>
|
<p><b>latest_fulldump</b> - a dictionary of the following structure:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>revision</b> - revision of the database saved in the latest fulldump,</li>
|
<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>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</b> - size of the file, in bytes,</li>
|
||||||
<li><b>size_uncompressed</b> - approximate size of the uncompressed contents, in bytes.</li>
|
<li><b>size_uncompressed</b> - approximate size of the uncompressed contents, in bytes.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -13,27 +13,27 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$internal_id = $request->get_parameter('internal_id');
|
$internal_id = $request->get_parameter('internal_id');
|
||||||
if (!$internal_id) throw new ParamMissing('internal_id');
|
if (!$internal_id) throw new ParamMissing('internal_id');
|
||||||
$fields = $request->get_parameter('fields');
|
$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(
|
$results = OkapiServiceRunner::call('services/users/by_internal_ids', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('internal_ids' => $internal_id,
|
$request->consumer, $request->token, array('internal_ids' => $internal_id,
|
||||||
'fields' => $fields)));
|
'fields' => $fields)));
|
||||||
$result = $results[$internal_id];
|
$result = $results[$internal_id];
|
||||||
if ($result == null)
|
if ($result == null)
|
||||||
throw new InvalidParam('internal_id', "There is no user by this internal_id.");
|
throw new InvalidParam('internal_id', "There is no user by this internal_id.");
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Find single user, by his internal_id</brief>
|
<brief>Find single user, by his internal_id</brief>
|
||||||
<issue-id>44</issue-id>
|
<issue-id>44</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Retrieve information on a single user, referencing him by his <b>internal</b> ID.</p>
|
<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
|
<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
|
normal ID - <b>user_uuid</b>. Also, internal IDs are not universally unique and are
|
||||||
a poor choice for a key.</p>
|
a poor choice for a key.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='internal_id'>Internal ID</req>
|
<req name='internal_id'>Internal ID</req>
|
||||||
<req name='fields'>
|
<req name='fields'>
|
||||||
<p>See services/users/user method.</p>
|
<p>See services/users/user method.</p>
|
||||||
</req>
|
</req>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>See services/users/user method.</p>
|
<p>See services/users/user method.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -13,56 +13,56 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$internal_ids = $request->get_parameter('internal_ids');
|
$internal_ids = $request->get_parameter('internal_ids');
|
||||||
if (!$internal_ids) throw new ParamMissing('internal_ids');
|
if (!$internal_ids) throw new ParamMissing('internal_ids');
|
||||||
$internal_ids = explode("|", $internal_ids);
|
$internal_ids = explode("|", $internal_ids);
|
||||||
if (count($internal_ids) > 500)
|
if (count($internal_ids) > 500)
|
||||||
throw new InvalidParam('internal_ids', "Maximum allowed number of referenced users ".
|
throw new InvalidParam('internal_ids', "Maximum allowed number of referenced users ".
|
||||||
"is 500. You provided ".count($internal_ids)." references.");
|
"is 500. You provided ".count($internal_ids)." references.");
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields)
|
if (!$fields)
|
||||||
throw new ParamMissing('fields');
|
throw new ParamMissing('fields');
|
||||||
|
|
||||||
# There's no need to validate the fields parameter as the 'users'
|
# There's no need to validate the fields parameter as the 'users'
|
||||||
# method does this (it will raise a proper exception on invalid values).
|
# method does this (it will raise a proper exception on invalid values).
|
||||||
|
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select user_id, uuid
|
select user_id, uuid
|
||||||
from user
|
from user
|
||||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', $internal_ids))."')
|
where user_id in ('".implode("','", array_map('mysql_real_escape_string', $internal_ids))."')
|
||||||
");
|
");
|
||||||
$internalid2useruuid = array();
|
$internalid2useruuid = array();
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
{
|
{
|
||||||
$internalid2useruuid[$row['user_id']] = $row['uuid'];
|
$internalid2useruuid[$row['user_id']] = $row['uuid'];
|
||||||
}
|
}
|
||||||
mysql_free_result($rs);
|
mysql_free_result($rs);
|
||||||
|
|
||||||
# Retrieve data on given user_uuids.
|
# Retrieve data on given user_uuids.
|
||||||
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($internalid2useruuid)),
|
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($internalid2useruuid)),
|
||||||
'fields' => $fields)));
|
'fields' => $fields)));
|
||||||
|
|
||||||
# Map user_uuids to internal_ids. Also check which internal_ids were not found
|
# Map user_uuids to internal_ids. Also check which internal_ids were not found
|
||||||
# and mark them with null.
|
# and mark them with null.
|
||||||
$results = array();
|
$results = array();
|
||||||
foreach ($internal_ids as $internal_id)
|
foreach ($internal_ids as $internal_id)
|
||||||
{
|
{
|
||||||
if (!isset($internalid2useruuid[$internal_id]))
|
if (!isset($internalid2useruuid[$internal_id]))
|
||||||
$results[$internal_id] = null;
|
$results[$internal_id] = null;
|
||||||
else
|
else
|
||||||
$results[$internal_id] = $id_results[$internalid2useruuid[$internal_id]];
|
$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>
|
<xml>
|
||||||
<brief>Find multiple users, by their internal IDs</brief>
|
<brief>Find multiple users, by their internal IDs</brief>
|
||||||
<issue-id>45</issue-id>
|
<issue-id>45</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method works like the services/users/by_internal_id method, but works
|
<p>This method works like the services/users/by_internal_id method, but works
|
||||||
with multiple users (instead of only one).</p>
|
with multiple users (instead of only one).</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='internal_ids'>
|
<req name='internal_ids'>
|
||||||
<p>Pipe-separated list of internal user IDs. No more than 500 are allowed.</p>
|
<p>Pipe-separated list of internal user IDs. No more than 500 are allowed.</p>
|
||||||
</req>
|
</req>
|
||||||
<req name='fields'>
|
<req name='fields'>
|
||||||
<p>See services/users/user method.</p>
|
<p>See services/users/user method.</p>
|
||||||
</req>
|
</req>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary. Internal IDs you provide will be mapped to dictionary keys,
|
<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>
|
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>
|
<p>Value of <b>null</b> means that the given internal ID haven't been found.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -16,27 +16,27 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$username = $request->get_parameter('username');
|
$username = $request->get_parameter('username');
|
||||||
if (!$username) throw new ParamMissing('username');
|
if (!$username) throw new ParamMissing('username');
|
||||||
$fields = $request->get_parameter('fields');
|
$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(
|
$results = OkapiServiceRunner::call('services/users/by_usernames', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('usernames' => $username,
|
$request->consumer, $request->token, array('usernames' => $username,
|
||||||
'fields' => $fields)));
|
'fields' => $fields)));
|
||||||
$result = $results[$username];
|
$result = $results[$username];
|
||||||
if ($result == null)
|
if ($result == null)
|
||||||
throw new InvalidParam('username', "There is no user by this username.");
|
throw new InvalidParam('username', "There is no user by this username.");
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Find single user, by his/her username</brief>
|
<brief>Find single user, by his/her username</brief>
|
||||||
<issue-id>24</issue-id>
|
<issue-id>24</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>Retrieve information on a single user, referencing him by his username.</p>
|
<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><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
|
<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
|
of referenced users. You should not store usernames in your database, it is
|
||||||
much safer to reference them by their IDs.</p>
|
much safer to reference them by their IDs.</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='username'>Name of the user (case insensitive).</req>
|
<req name='username'>Name of the user (case insensitive).</req>
|
||||||
<req name='fields'>
|
<req name='fields'>
|
||||||
<p>Same as in the services/users/user method. Pipe-separated list
|
<p>Same as in the services/users/user method. Pipe-separated list
|
||||||
of field names which you are interested with.
|
of field names which you are interested with.
|
||||||
See services/users/user method for a list available values.</p>
|
See services/users/user method for a list available values.</p>
|
||||||
</req>
|
</req>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of fields you have selected.</p>
|
<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>
|
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -13,63 +13,63 @@ use okapi\OkapiInternalRequest;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$usernames = $request->get_parameter('usernames');
|
$usernames = $request->get_parameter('usernames');
|
||||||
if (!$usernames) throw new ParamMissing('usernames');
|
if (!$usernames) throw new ParamMissing('usernames');
|
||||||
$usernames = explode("|", $usernames);
|
$usernames = explode("|", $usernames);
|
||||||
if (count($usernames) > 500)
|
if (count($usernames) > 500)
|
||||||
throw new InvalidParam('usernames', "Maximum allowed number of referenced users ".
|
throw new InvalidParam('usernames', "Maximum allowed number of referenced users ".
|
||||||
"is 500. You provided ".count($usernames)." usernames.");
|
"is 500. You provided ".count($usernames)." usernames.");
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields)
|
if (!$fields)
|
||||||
throw new ParamMissing('fields');
|
throw new ParamMissing('fields');
|
||||||
|
|
||||||
# There's no need to validate the fields parameter as the 'users'
|
# There's no need to validate the fields parameter as the 'users'
|
||||||
# method does this (it will raise a proper exception on invalid values).
|
# method does this (it will raise a proper exception on invalid values).
|
||||||
|
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select username, uuid
|
select username, uuid
|
||||||
from user
|
from user
|
||||||
where username collate utf8_general_ci in ('".implode("','", array_map('mysql_real_escape_string', $usernames))."')
|
where username collate utf8_general_ci in ('".implode("','", array_map('mysql_real_escape_string', $usernames))."')
|
||||||
");
|
");
|
||||||
$lower_username2useruuid = array();
|
$lower_username2useruuid = array();
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
{
|
{
|
||||||
$lower_username2useruuid[mb_strtolower($row['username'], 'utf-8')] = $row['uuid'];
|
$lower_username2useruuid[mb_strtolower($row['username'], 'utf-8')] = $row['uuid'];
|
||||||
}
|
}
|
||||||
mysql_free_result($rs);
|
mysql_free_result($rs);
|
||||||
|
|
||||||
# Retrieve data for the found user_uuids.
|
# Retrieve data for the found user_uuids.
|
||||||
|
|
||||||
if (count($lower_username2useruuid) > 0)
|
if (count($lower_username2useruuid) > 0)
|
||||||
{
|
{
|
||||||
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($lower_username2useruuid)),
|
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($lower_username2useruuid)),
|
||||||
'fields' => $fields)));
|
'fields' => $fields)));
|
||||||
} else {
|
} else {
|
||||||
$id_results = array();
|
$id_results = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
# Map user_uuids back to usernames. Also check which usernames were not found
|
# Map user_uuids back to usernames. Also check which usernames were not found
|
||||||
# and mark them with null.
|
# and mark them with null.
|
||||||
|
|
||||||
$results = array();
|
$results = array();
|
||||||
foreach ($usernames as $username)
|
foreach ($usernames as $username)
|
||||||
{
|
{
|
||||||
if (!isset($lower_username2useruuid[mb_strtolower($username, 'utf-8')]))
|
if (!isset($lower_username2useruuid[mb_strtolower($username, 'utf-8')]))
|
||||||
$results[$username] = null;
|
$results[$username] = null;
|
||||||
else
|
else
|
||||||
$results[$username] = $id_results[$lower_username2useruuid[mb_strtolower($username, 'utf-8')]];
|
$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>
|
<xml>
|
||||||
<brief>Find multiple users, by their usernames</brief>
|
<brief>Find multiple users, by their usernames</brief>
|
||||||
<issue-id>25</issue-id>
|
<issue-id>25</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
<p>This method works like the services/users/by_username method, but works
|
<p>This method works like the services/users/by_username method, but works
|
||||||
with multiple users (instead of only one).</p>
|
with multiple users (instead of only one).</p>
|
||||||
</desc>
|
</desc>
|
||||||
<req name='usernames'>
|
<req name='usernames'>
|
||||||
<p>Pipe-separated list of usernames. No more than 500 are allowed.</p>
|
<p>Pipe-separated list of usernames. No more than 500 are allowed.</p>
|
||||||
</req>
|
</req>
|
||||||
<req name='fields'>
|
<req name='fields'>
|
||||||
<p>Same as in the services/users/user method. Pipe-separated list
|
<p>Same as in the services/users/user method. Pipe-separated list
|
||||||
of field names which you are interested with.
|
of field names which you are interested with.
|
||||||
See services/users/user method for a list available values.</p>
|
See services/users/user method for a list available values.</p>
|
||||||
</req>
|
</req>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary. Usernames you provide will be mapped to dictionary keys,
|
<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>
|
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.
|
<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
|
(This behavior is different than in the services/users/by_username method, which
|
||||||
responds with an HTTP 400 error in such case.)</p>
|
responds with an HTTP 400 error in such case.)</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -16,41 +16,41 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$user_uuid = $request->get_parameter('user_uuid');
|
$user_uuid = $request->get_parameter('user_uuid');
|
||||||
if (!$user_uuid)
|
if (!$user_uuid)
|
||||||
{
|
{
|
||||||
if ($request->token)
|
if ($request->token)
|
||||||
{
|
{
|
||||||
$tmp = OkapiServiceRunner::call('services/users/by_internal_id', new OkapiInternalRequest(
|
$tmp = OkapiServiceRunner::call('services/users/by_internal_id', new OkapiInternalRequest(
|
||||||
$request->consumer, null, array('internal_id' => $request->token->user_id, 'fields' => 'uuid')));
|
$request->consumer, null, array('internal_id' => $request->token->user_id, 'fields' => 'uuid')));
|
||||||
$user_uuid = $tmp['uuid'];
|
$user_uuid = $tmp['uuid'];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new BadRequest("You must either: 1. supply the user_uuid argument, or "
|
throw new BadRequest("You must either: 1. supply the user_uuid argument, or "
|
||||||
."2. sign your request with an Access Token.");
|
."2. sign your request with an Access Token.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
|
|
||||||
# There's no need to validate the fields parameter as the 'users'
|
# There's no need to validate the fields parameter as the 'users'
|
||||||
# method does this (it will raise a proper exception on invalid values).
|
# method does this (it will raise a proper exception on invalid values).
|
||||||
|
|
||||||
$results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
$results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||||
$request->consumer, $request->token, array('user_uuids' => $user_uuid,
|
$request->consumer, $request->token, array('user_uuids' => $user_uuid,
|
||||||
'fields' => $fields)));
|
'fields' => $fields)));
|
||||||
$result = $results[$user_uuid];
|
$result = $results[$user_uuid];
|
||||||
if ($result == null)
|
if ($result == null)
|
||||||
throw new InvalidParam('user_uuid', "There is no user by this ID.");
|
throw new InvalidParam('user_uuid', "There is no user by this ID.");
|
||||||
return Okapi::formatted_response($request, $result);
|
return Okapi::formatted_response($request, $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,45 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<brief>Retrieve information on a single user</brief>
|
<brief>Retrieve information on a single user</brief>
|
||||||
<issue-id>26</issue-id>
|
<issue-id>26</issue-id>
|
||||||
<desc>
|
<desc>
|
||||||
Retrieve information on a single user. This method might be also used
|
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
|
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>
|
issued. To do this, include the Access Token in your request, and <b>don't</b>
|
||||||
include the user_uuid argument.
|
include the user_uuid argument.
|
||||||
</desc>
|
</desc>
|
||||||
<req name='fields'>
|
<req name='fields'>
|
||||||
<p>Pipe-separated list of field names which you are interested with.
|
<p>Pipe-separated list of field names which you are interested with.
|
||||||
Selected fields will be included in the response. See below for the
|
Selected fields will be included in the response. See below for the
|
||||||
list of available fields.</p>
|
list of available fields.</p>
|
||||||
</req>
|
</req>
|
||||||
<opt name='user_uuid'>
|
<opt name='user_uuid'>
|
||||||
<p>ID of the user.</p>
|
<p>ID of the user.</p>
|
||||||
<p>This parameter is optional only when you sign your
|
<p>This parameter is optional only when you sign your
|
||||||
request with an Access Token (Level 3 Authentication). Otherwise,
|
request with an Access Token (Level 3 Authentication). Otherwise,
|
||||||
it is <b>required</b>.</p>
|
it is <b>required</b>.</p>
|
||||||
</opt>
|
</opt>
|
||||||
<common-format-params/>
|
<common-format-params/>
|
||||||
<returns>
|
<returns>
|
||||||
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
<p>A dictionary of fields you have selected. Currently available fields:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>uuid</b> - ID of the user,</li>
|
<li><b>uuid</b> - ID of the user,</li>
|
||||||
<li><b>username</b> - username (login) 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><b>profile_url</b> - URL of the user's Opencaching profile page,</li>
|
||||||
<li>
|
<li>
|
||||||
<p><b>is_admin</b> - boolean; true is user has admin privileges.</p>
|
<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
|
<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
|
and only for the user of your Access Token. For all other reads, is_admin
|
||||||
will equal <b>null</b>.</p>
|
will equal <b>null</b>.</p>
|
||||||
</li>
|
</li>
|
||||||
<li><b>internal_id</b> - internal ID of the user (<b>DO NOT</b> use this!
|
<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>
|
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_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_notfound</b> - number of "Didn't find it" log entries,</li>
|
||||||
<li><b>caches_hidden</b> - number of caches owned,</li>
|
<li><b>caches_hidden</b> - number of caches owned,</li>
|
||||||
<li><b>rcmds_given</b> - number of recommendations given.</li>
|
<li><b>rcmds_given</b> - number of recommendations given.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
||||||
</returns>
|
</returns>
|
||||||
</xml>
|
</xml>
|
||||||
@@ -13,154 +13,154 @@ use okapi\services\caches\search\SearchAssistant;
|
|||||||
|
|
||||||
class WebService
|
class WebService
|
||||||
{
|
{
|
||||||
public static function options()
|
public static function options()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'min_auth_level' => 1
|
'min_auth_level' => 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static $valid_field_names = array('uuid', 'username', 'profile_url', 'internal_id', 'is_admin',
|
private static $valid_field_names = array('uuid', 'username', 'profile_url', 'internal_id', 'is_admin',
|
||||||
'caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given');
|
'caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given');
|
||||||
|
|
||||||
public static function call(OkapiRequest $request)
|
public static function call(OkapiRequest $request)
|
||||||
{
|
{
|
||||||
$user_uuids = $request->get_parameter('user_uuids');
|
$user_uuids = $request->get_parameter('user_uuids');
|
||||||
if (!$user_uuids) throw new ParamMissing('user_uuids');
|
if (!$user_uuids) throw new ParamMissing('user_uuids');
|
||||||
$user_uuids = explode("|", $user_uuids);
|
$user_uuids = explode("|", $user_uuids);
|
||||||
if (count($user_uuids) > 500)
|
if (count($user_uuids) > 500)
|
||||||
throw new InvalidParam('user_uuids', "Maximum allowed number of referenced users ".
|
throw new InvalidParam('user_uuids', "Maximum allowed number of referenced users ".
|
||||||
"is 500. You provided ".count($user_uuids)." user IDs.");
|
"is 500. You provided ".count($user_uuids)." user IDs.");
|
||||||
$fields = $request->get_parameter('fields');
|
$fields = $request->get_parameter('fields');
|
||||||
if (!$fields)
|
if (!$fields)
|
||||||
throw new ParamMissing('fields');
|
throw new ParamMissing('fields');
|
||||||
$fields = explode("|", $fields);
|
$fields = explode("|", $fields);
|
||||||
foreach ($fields as $field)
|
foreach ($fields as $field)
|
||||||
if (!in_array($field, self::$valid_field_names))
|
if (!in_array($field, self::$valid_field_names))
|
||||||
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select user_id, uuid, username, admin
|
select user_id, uuid, username, admin
|
||||||
from user
|
from user
|
||||||
where uuid in ('".implode("','", array_map('mysql_real_escape_string', $user_uuids))."')
|
where uuid in ('".implode("','", array_map('mysql_real_escape_string', $user_uuids))."')
|
||||||
");
|
");
|
||||||
$results = array();
|
$results = array();
|
||||||
$id2uuid = array();
|
$id2uuid = array();
|
||||||
$uuid2id = array();
|
$uuid2id = array();
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
{
|
{
|
||||||
$id2uuid[$row['user_id']] = $row['uuid'];
|
$id2uuid[$row['user_id']] = $row['uuid'];
|
||||||
$uuid2id[$row['uuid']] = $row['user_id'];
|
$uuid2id[$row['uuid']] = $row['user_id'];
|
||||||
$entry = array();
|
$entry = array();
|
||||||
foreach ($fields as $field)
|
foreach ($fields as $field)
|
||||||
{
|
{
|
||||||
switch ($field)
|
switch ($field)
|
||||||
{
|
{
|
||||||
case 'uuid': $entry['uuid'] = $row['uuid']; break;
|
case 'uuid': $entry['uuid'] = $row['uuid']; break;
|
||||||
case 'username': $entry['username'] = $row['username']; 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 'profile_url': $entry['profile_url'] = Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id']; break;
|
||||||
case 'is_admin':
|
case 'is_admin':
|
||||||
if (!$request->token) {
|
if (!$request->token) {
|
||||||
$entry['is_admin'] = null;
|
$entry['is_admin'] = null;
|
||||||
} elseif ($request->token->user_id != $row['user_id']) {
|
} elseif ($request->token->user_id != $row['user_id']) {
|
||||||
$entry['is_admin'] = null;
|
$entry['is_admin'] = null;
|
||||||
} else {
|
} else {
|
||||||
$entry['is_admin'] = $row['admin'] ? true : false;
|
$entry['is_admin'] = $row['admin'] ? true : false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'internal_id': $entry['internal_id'] = $row['user_id']; break;
|
case 'internal_id': $entry['internal_id'] = $row['user_id']; break;
|
||||||
case 'caches_found': /* handled separately */ break;
|
case 'caches_found': /* handled separately */ break;
|
||||||
case 'caches_notfound': /* handled separately */ break;
|
case 'caches_notfound': /* handled separately */ break;
|
||||||
case 'caches_hidden': /* handled separately */ break;
|
case 'caches_hidden': /* handled separately */ break;
|
||||||
case 'rcmds_given': /* handled separately */ break;
|
case 'rcmds_given': /* handled separately */ break;
|
||||||
default: throw new Exception("Missing field case: ".$field);
|
default: throw new Exception("Missing field case: ".$field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$results[$row['uuid']] = $entry;
|
$results[$row['uuid']] = $entry;
|
||||||
}
|
}
|
||||||
mysql_free_result($rs);
|
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)
|
if (in_array('caches_found', $fields) || in_array('caches_notfound', $fields) || in_array('caches_hidden', $fields)
|
||||||
|| in_array('rcmds_given', $fields))
|
|| in_array('rcmds_given', $fields))
|
||||||
{
|
{
|
||||||
# We will load all these stats together. Then we may remove these which
|
# We will load all these stats together. Then we may remove these which
|
||||||
# the user doesn't need.
|
# the user doesn't need.
|
||||||
|
|
||||||
$extras = array();
|
$extras = array();
|
||||||
|
|
||||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||||
{
|
{
|
||||||
# OCPL stores user stats in 'user' table.
|
# OCPL stores user stats in 'user' table.
|
||||||
|
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select user_id, founds_count, notfounds_count, hidden_count
|
select user_id, founds_count, notfounds_count, hidden_count
|
||||||
from user
|
from user
|
||||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
where user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
# OCDE stores user stats in 'stat_user' table.
|
# OCDE stores user stats in 'stat_user' table.
|
||||||
|
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select
|
select
|
||||||
u.user_id,
|
u.user_id,
|
||||||
ifnull(su.found, 0) as founds_count,
|
ifnull(su.found, 0) as founds_count,
|
||||||
ifnull(su.notfound, 0) as notfounds_count,
|
ifnull(su.notfound, 0) as notfounds_count,
|
||||||
ifnull(su.hidden, 0) as hidden_count
|
ifnull(su.hidden, 0) as hidden_count
|
||||||
from
|
from
|
||||||
user u
|
user u
|
||||||
left join stat_user su
|
left join stat_user su
|
||||||
on su.user_id = u.user_id
|
on su.user_id = u.user_id
|
||||||
where u.user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
where u.user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
{
|
{
|
||||||
$extras[$row['user_id']] = array();;
|
$extras[$row['user_id']] = array();;
|
||||||
$extra_ref = &$extras[$row['user_id']];
|
$extra_ref = &$extras[$row['user_id']];
|
||||||
$extra_ref['caches_found'] = 0 + $row['founds_count'];
|
$extra_ref['caches_found'] = 0 + $row['founds_count'];
|
||||||
$extra_ref['caches_notfound'] = 0 + $row['notfounds_count'];
|
$extra_ref['caches_notfound'] = 0 + $row['notfounds_count'];
|
||||||
$extra_ref['caches_hidden'] = 0 + $row['hidden_count'];
|
$extra_ref['caches_hidden'] = 0 + $row['hidden_count'];
|
||||||
}
|
}
|
||||||
mysql_free_result($rs);
|
mysql_free_result($rs);
|
||||||
|
|
||||||
if (in_array('rcmds_given', $fields))
|
if (in_array('rcmds_given', $fields))
|
||||||
{
|
{
|
||||||
$rs = Db::query("
|
$rs = Db::query("
|
||||||
select user_id, count(*) as rcmds_given
|
select user_id, count(*) as rcmds_given
|
||||||
from cache_rating
|
from cache_rating
|
||||||
where user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
where user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||||
group by user_id
|
group by user_id
|
||||||
");
|
");
|
||||||
$rcmds_counts = array();
|
$rcmds_counts = array();
|
||||||
while ($row = mysql_fetch_assoc($rs))
|
while ($row = mysql_fetch_assoc($rs))
|
||||||
$rcmds_counts[$row['user_id']] = $row['rcmds_given'];
|
$rcmds_counts[$row['user_id']] = $row['rcmds_given'];
|
||||||
foreach ($extras as $user_id => &$extra_ref)
|
foreach ($extras as $user_id => &$extra_ref)
|
||||||
{
|
{
|
||||||
$extra_ref['rcmds_given'] = isset($rcmds_counts[$user_id]) ? 0 + $rcmds_counts[$user_id] : 0;
|
$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)
|
foreach (array('caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given') as $field)
|
||||||
{
|
{
|
||||||
if (!in_array($field, $fields))
|
if (!in_array($field, $fields))
|
||||||
continue;
|
continue;
|
||||||
foreach ($results as $uuid => &$result_ref)
|
foreach ($results as $uuid => &$result_ref)
|
||||||
$result_ref[$field] = $extras[$uuid2id[$uuid]][$field];
|
$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)
|
foreach ($user_uuids as $user_uuid)
|
||||||
if (!isset($results[$user_uuid]))
|
if (!isset($results[$user_uuid]))
|
||||||
$results[$user_uuid] = null;
|
$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
Reference in New Issue
Block a user