@@ -759,7 +759,7 @@ class Okapi
|
||||
{
|
||||
public static $data_store;
|
||||
public static $server;
|
||||
public static $revision = 500; # This gets replaced in automatically deployed packages
|
||||
public static $revision = 554; # This gets replaced in automatically deployed packages
|
||||
private static $okapi_vars = null;
|
||||
|
||||
/** Get a variable stored in okapi_vars. If variable not found, return $default. */
|
||||
@@ -1079,6 +1079,7 @@ class Okapi
|
||||
if ($init_made)
|
||||
return;
|
||||
ini_set('memory_limit', '128M');
|
||||
Db::connect();
|
||||
if (!self::$data_store)
|
||||
self::$data_store = new OkapiDataStore();
|
||||
if (!self::$server)
|
||||
@@ -1223,9 +1224,11 @@ class Okapi
|
||||
return $names[round(($b / 360.0) * 16.0) % 16];
|
||||
}
|
||||
|
||||
/** Escape string for use with XML. */
|
||||
public static function xmlentities($string)
|
||||
/** Escape string for use with XML. See issue 169. */
|
||||
public static function xmlescape($string)
|
||||
{
|
||||
static $pattern = '/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u';
|
||||
$string = preg_replace($pattern, '', $string);
|
||||
return strtr($string, array("<" => "<", ">" => ">", "\"" => """, "'" => "'", "&" => "&"));
|
||||
}
|
||||
|
||||
@@ -1296,7 +1299,7 @@ class Okapi
|
||||
if (is_string($obj))
|
||||
{
|
||||
$chunks[] = "<string>";
|
||||
$chunks[] = self::xmlentities($obj);
|
||||
$chunks[] = self::xmlescape($obj);
|
||||
$chunks[] = "</string>";
|
||||
}
|
||||
elseif (is_int($obj))
|
||||
@@ -1336,7 +1339,7 @@ class Okapi
|
||||
$chunks[] = "<dict>";
|
||||
foreach ($obj as $key => &$item_ref)
|
||||
{
|
||||
$chunks[] = "<item key=\"".self::xmlentities($key)."\">";
|
||||
$chunks[] = "<item key=\"".self::xmlescape($key)."\">";
|
||||
self::_xmlmap_add($chunks, $item_ref);
|
||||
$chunks[] = "</item>";
|
||||
}
|
||||
@@ -1352,11 +1355,11 @@ class Okapi
|
||||
|
||||
private static function _xmlmap2_add(&$chunks, &$obj, $key)
|
||||
{
|
||||
$attrs = ($key !== null) ? " key=\"".self::xmlentities($key)."\"" : "";
|
||||
$attrs = ($key !== null) ? " key=\"".self::xmlescape($key)."\"" : "";
|
||||
if (is_string($obj))
|
||||
{
|
||||
$chunks[] = "<string$attrs>";
|
||||
$chunks[] = self::xmlentities($obj);
|
||||
$chunks[] = self::xmlescape($obj);
|
||||
$chunks[] = "</string>";
|
||||
}
|
||||
elseif (is_int($obj))
|
||||
@@ -1436,15 +1439,17 @@ class Okapi
|
||||
'oc.pl' => array(
|
||||
# Primary types (documented, cannot change)
|
||||
'Traditional' => 2, 'Multi' => 3, 'Quiz' => 7, 'Virtual' => 4,
|
||||
'Event' => 6,
|
||||
# Additional types (may get changed)
|
||||
'Other' => 1, 'Webcam' => 5, 'Event' => 6,
|
||||
'Other' => 1, 'Webcam' => 5,
|
||||
'Moving' => 8, 'Podcast' => 9, 'Own' => 10,
|
||||
),
|
||||
'oc.de' => array(
|
||||
# Primary types (documented, cannot change)
|
||||
'Traditional' => 2, 'Multi' => 3, 'Quiz' => 7, 'Virtual' => 4,
|
||||
'Event' => 6,
|
||||
# Additional types (might get changed)
|
||||
'Other' => 1, 'Webcam' => 5, 'Event' => 6,
|
||||
'Other' => 1, 'Webcam' => 5,
|
||||
'Math/Physics' => 8, 'Moving' => 9, 'Drive-In' => 10,
|
||||
)
|
||||
);
|
||||
@@ -1568,6 +1573,8 @@ class Okapi
|
||||
if ($name == 'Found it') return 1;
|
||||
if ($name == "Didn't find it") return 2;
|
||||
if ($name == 'Comment') return 3;
|
||||
if ($name == 'Attended') return 7;
|
||||
if ($name == 'Will attend') return 8;
|
||||
if (($name == 'Needs maintenance') && (Settings::get('SUPPORTS_LOGTYPE_NEEDS_MAINTENANCE')))
|
||||
return 5;
|
||||
throw new Exception("logtype2id called with invalid log type argument: $name");
|
||||
@@ -1584,6 +1591,8 @@ class Okapi
|
||||
if ($id == 1) return "Found it";
|
||||
if ($id == 2) return "Didn't find it";
|
||||
if ($id == 3) return "Comment";
|
||||
if ($id == 7) return "Attended";
|
||||
if ($id == 8) return "Will attend";
|
||||
|
||||
static $other_types = null;
|
||||
if ($other_types === null)
|
||||
|
@@ -49,6 +49,7 @@ class CronJobController
|
||||
new LocaleChecker(),
|
||||
new FulldumpGeneratorJob(),
|
||||
new TileTreeUpdater(),
|
||||
new SearchSetsCleanerJob(),
|
||||
);
|
||||
foreach ($cache as $cronjob)
|
||||
if (!in_array($cronjob->get_type(), array('pre-request', 'cron-5')))
|
||||
@@ -261,6 +262,24 @@ class OAuthCleanupCronJob extends PrerequestCronJob
|
||||
}
|
||||
}
|
||||
|
||||
/** Clean up the saved search tables, every 10 minutes. */
|
||||
class SearchSetsCleanerJob extends Cron5Job
|
||||
{
|
||||
public function get_period() { return 600; }
|
||||
public function execute()
|
||||
{
|
||||
Db::execute("
|
||||
delete oss, osr
|
||||
from
|
||||
okapi_search_sets oss
|
||||
left join okapi_search_results osr
|
||||
on oss.id = osr.set_id
|
||||
where
|
||||
date_add(oss.expires, interval 60 second) < now()
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
/** Clean up the cache, once per hour. */
|
||||
class CacheCleanupCronJob extends Cron5Job
|
||||
{
|
||||
@@ -413,7 +432,7 @@ class CheckCronTab2 extends PrerequestCronJob
|
||||
# There was a ping during the last hour. Everything is okay.
|
||||
# Reset the counter and return.
|
||||
|
||||
Cache::set('crontab_check_counter', 3, 86400);
|
||||
Cache::set('crontab_check_counter', 5, 86400);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -421,7 +440,7 @@ class CheckCronTab2 extends PrerequestCronJob
|
||||
|
||||
$counter = Cache::get('crontab_check_counter');
|
||||
if ($counter === null)
|
||||
$counter = 3;
|
||||
$counter = 5;
|
||||
$counter--;
|
||||
if ($counter > 0)
|
||||
{
|
||||
@@ -522,8 +541,11 @@ class TileTreeUpdater extends Cron5Job
|
||||
# not working for more than 10 days. Or, just after OKAPI
|
||||
# is installed (and this is the first time this cronjob
|
||||
# if being run).
|
||||
\okapi\services\caches\map\ReplicateListener::reset();
|
||||
|
||||
$mail_admins = ($tiletree_revision > 0);
|
||||
\okapi\services\caches\map\ReplicateListener::reset($mail_admins);
|
||||
Okapi::set_var('clog_followup_revision', $current_clog_revision);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@@ -31,6 +31,7 @@ use okapi\OkapiFacadeAccessToken;
|
||||
require_once($GLOBALS['rootpath']."okapi/core.php");
|
||||
OkapiErrorHandler::$treat_notices_as_errors = true;
|
||||
require_once($GLOBALS['rootpath']."okapi/service_runner.php");
|
||||
Okapi::init_internals();
|
||||
|
||||
/**
|
||||
* Use this class to access OKAPI's services from external code (i.e. OC code).
|
||||
@@ -73,4 +74,28 @@ class Facade
|
||||
$response = OkapiServiceRunner::call($service_name, $request);
|
||||
$response->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a search set from a temporary table. This is very similar to
|
||||
* the "services/caches/search/save" method, but allows OC server to
|
||||
* include its own result instead of using OKAPI's search options. The
|
||||
* $temp_table should be a valid name of a temporary table with the
|
||||
* following (or similar) structure:
|
||||
*
|
||||
* create temporary table temp_12345 (
|
||||
* cache_id integer primary key
|
||||
* ) engine=memory;
|
||||
*/
|
||||
public static function import_search_set($temp_table, $min_store, $max_ref_age)
|
||||
{
|
||||
require_once 'services/caches/search/save.php';
|
||||
$tables = array('caches', $temp_table);
|
||||
$where_conds = array(
|
||||
$temp_table.".cache_id = caches.cache_id",
|
||||
'caches.status in (1,2,3)',
|
||||
);
|
||||
return \okapi\services\caches\search\save\WebService::get_set(
|
||||
$tables, $where_conds, $min_store, $max_ref_age
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -30,9 +30,11 @@ class OkapiServiceRunner
|
||||
'services/caches/search/bbox',
|
||||
'services/caches/search/nearest',
|
||||
'services/caches/search/by_urls',
|
||||
'services/caches/search/save',
|
||||
'services/caches/shortcuts/search_and_retrieve',
|
||||
'services/caches/geocache',
|
||||
'services/caches/geocaches',
|
||||
'services/caches/mark',
|
||||
'services/caches/formatters/gpx',
|
||||
'services/caches/formatters/garmin',
|
||||
'services/caches/map/tile',
|
||||
|
@@ -96,17 +96,20 @@ class WebService
|
||||
$referenced_method_info = OkapiServiceRunner::call('services/apiref/method',
|
||||
new OkapiInternalRequest(new OkapiInternalConsumer(), null, array('name' => $referenced_methodname)));
|
||||
$include_list = isset($attrs['params']) ? explode("|", $attrs['params']) : null;
|
||||
$exclude_list = isset($attrs['except']) ? explode("|", $attrs['except']) : array();
|
||||
foreach ($referenced_method_info['arguments'] as $arg)
|
||||
{
|
||||
if ($arg['class'] == 'common-formatting')
|
||||
continue;
|
||||
if ($include_list === null)
|
||||
if (($include_list === null) && (count($exclude_list) == 0))
|
||||
{
|
||||
$arg['description'] = "<i>Inherited from <a href='".$referenced_method_info['ref_url'].
|
||||
"'>".$referenced_method_info['name']."</a> method.</i>";
|
||||
}
|
||||
elseif (in_array($arg['name'], $include_list))
|
||||
{
|
||||
elseif (
|
||||
(($include_list === null) || in_array($arg['name'], $include_list))
|
||||
&& (!in_array($arg['name'], $exclude_list))
|
||||
) {
|
||||
$arg['description'] = "<i>Same as in the <a href='".$referenced_method_info['ref_url'].
|
||||
"'>".$referenced_method_info['name']."</a> method.</i>";
|
||||
} else {
|
||||
|
@@ -27,10 +27,10 @@
|
||||
<ul>
|
||||
<li><b>min_auth_level</b> - integer, in range from 0 to 3,
|
||||
see Introduction page.</li>
|
||||
<li><b>oauth_consumer</b> - "required" when min_auth_level >= 2,
|
||||
"optional" otherwise,</li>
|
||||
<li><b>oauth_token</b> - "required" when min_auth_level == 3,
|
||||
"optional" otherwise.</li>
|
||||
<li><b>oauth_consumer</b> - true, if requests are required to be signed
|
||||
with OAuth Consumer Key (min_auth_level >= 2),</li>
|
||||
<li><b>oauth_token</b> - true, if requests are required to include an
|
||||
OAuth Token (min_auth_level == 3).</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><b>arguments</b> - list of dictionaries, describes method
|
||||
|
@@ -24,12 +24,12 @@ class WebService
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cache_key = "api_ref/method_index";
|
||||
$methodnames = OkapiServiceRunner::$all_names;
|
||||
sort($methodnames);
|
||||
$cache_key = "api_ref/method_index#".md5(implode("#", $methodnames));
|
||||
$results = Cache::get($cache_key);
|
||||
if ($results == null)
|
||||
{
|
||||
$methodnames = OkapiServiceRunner::$all_names;
|
||||
sort($methodnames);
|
||||
$results = array();
|
||||
foreach ($methodnames as $methodname)
|
||||
{
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace okapi\services\caches\formatters\garmin;
|
||||
|
||||
use okapi\Okapi;
|
||||
use okapi\Cache;
|
||||
use okapi\Settings;
|
||||
use okapi\OkapiRequest;
|
||||
use okapi\OkapiHttpResponse;
|
||||
@@ -15,6 +16,7 @@ use okapi\OkapiAccessToken;
|
||||
use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
use \ZipArchive;
|
||||
use \Exception;
|
||||
|
||||
class WebService
|
||||
{
|
||||
@@ -45,7 +47,7 @@ class WebService
|
||||
|
||||
# Start creating ZIP archive.
|
||||
|
||||
$tempfilename = sys_get_temp_dir()."/garmin".time().rand(100000,999999).".zip";
|
||||
$tempfilename = Okapi::get_var_dir()."/garmin".time().rand(100000,999999).".zip";
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($tempfilename, ZIPARCHIVE::CREATE) !== true)
|
||||
throw new Exception("ZipArchive class could not create temp file $tempfilename. Check permissions!");
|
||||
@@ -87,6 +89,7 @@ class WebService
|
||||
throw new InvalidParam('cache_codes', "The maximum number of caches allowed to be downloaded with this method is 50.");
|
||||
if ($images != 'none')
|
||||
{
|
||||
$supported_extensions = array('jpg', 'jpeg', 'gif', 'png', 'bmp');
|
||||
foreach ($caches as $cache_code => $dict)
|
||||
{
|
||||
$imgs = $dict['images'];
|
||||
@@ -104,8 +107,18 @@ class WebService
|
||||
continue;
|
||||
if ($images == 'nonspoilers' && $img['is_spoiler'])
|
||||
continue;
|
||||
if (strtolower(substr($img['url'], strlen($img['url']) - 4)) != ".jpg")
|
||||
continue;
|
||||
$tmp = false;
|
||||
foreach ($supported_extensions as $ext)
|
||||
{
|
||||
if (strtolower(substr($img['url'], strlen($img['url']) - strlen($ext) - 1)) != ".".$ext)
|
||||
{
|
||||
$tmp = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!$tmp)
|
||||
continue; # unsupported file extension
|
||||
|
||||
if ($img['is_spoiler']) {
|
||||
$zip->addEmptyDir($dir."/Spoilers");
|
||||
$zippath = $dir."/Spoilers/".$img['unique_caption'].".jpg";
|
||||
@@ -121,11 +134,50 @@ class WebService
|
||||
# be accessed locally. But all the files have 'local' set to 1 anyway.
|
||||
|
||||
$syspath = Settings::get('IMAGES_DIR')."/".$img['uuid'].".jpg";
|
||||
if (!file_exists($syspath))
|
||||
continue;
|
||||
$file = file_get_contents($syspath);
|
||||
if ($file)
|
||||
$zip->addFromString($zippath, $file);
|
||||
if (file_exists($syspath))
|
||||
{
|
||||
$file = file_get_contents($syspath);
|
||||
if ($file)
|
||||
$zip->addFromString($zippath, $file);
|
||||
}
|
||||
else
|
||||
{
|
||||
# If file exists, but does not end with ".jpg", we will create
|
||||
# JPEG version of it and store it in the cache.
|
||||
|
||||
$cache_key = "jpg#".$img['uuid'];
|
||||
$jpeg_contents = Cache::get($cache_key);
|
||||
if ($jpeg_contents === null)
|
||||
{
|
||||
foreach ($supported_extensions as $ext)
|
||||
{
|
||||
$syspath_other = Settings::get('IMAGES_DIR')."/".$img['uuid'].".".$ext;
|
||||
if (file_exists($syspath_other))
|
||||
{
|
||||
try
|
||||
{
|
||||
$image = imagecreatefromstring(file_get_contents($syspath_other));
|
||||
ob_start();
|
||||
imagejpeg($image);
|
||||
$jpeg_contents = ob_get_clean();
|
||||
imagedestroy($image);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# GD couldn't parse the file. We will skip it, and cache
|
||||
# the "false" value as the contents. This way, we won't
|
||||
# attempt to parse it during the next 24 hours.
|
||||
|
||||
$jpeg_contents = false;
|
||||
}
|
||||
Cache::set($cache_key, $jpeg_contents, 86400);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($jpeg_contents) # This can be "null" *or* "false"!
|
||||
$zip->addFromString($zippath, $jpeg_contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,9 @@
|
||||
<?
|
||||
|
||||
namespace okapi\services\caches\formatters\gpx;
|
||||
|
||||
use okapi\Okapi;
|
||||
|
||||
echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
|
||||
|
||||
?>
|
||||
@@ -24,24 +28,24 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
||||
<time><?= $c['date_created'] ?></time>
|
||||
<name><?= $c['code'] ?></name>
|
||||
<desc><?= htmlspecialchars($c['name'], ENT_COMPAT, 'UTF-8') ?> <?= _("hidden by") ?> <?= htmlspecialchars($c['owner']['username'], ENT_COMPAT, 'UTF-8') ?> :: <?= 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>
|
||||
<urlname><?= htmlspecialchars($c['name'], ENT_COMPAT, 'UTF-8') ?></urlname>
|
||||
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
||||
<sym><?= ($vars['mark_found'] && $c['is_found']) ? "Geocache Found" : "Geocache" ?></sym>
|
||||
<type>Geocache|<?= $vars['cache_GPX_types'][$c['type']] ?></type>
|
||||
<? if ($vars['ns_ground']) { /* Does user want us to include Groundspeak's <cache> element? */ ?>
|
||||
<groundspeak:cache archived="<?= ($c['status'] == 'Archived') ? "True" : "False" ?>" available="<?= ($c['status'] == 'Available') ? "True" : "False" ?>" id="<?= $c['internal_id'] ?>" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0/1">
|
||||
<groundspeak:name><?= htmlspecialchars($c['name'], ENT_COMPAT, 'UTF-8') ?></groundspeak:name>
|
||||
<groundspeak:placed_by><?= htmlspecialchars($c['owner']['username'], ENT_COMPAT, 'UTF-8') ?></groundspeak:placed_by>
|
||||
<groundspeak:owner id="<?= $c['owner']['uuid'] ?>"><?= htmlspecialchars($c['owner']['username'], ENT_COMPAT, 'UTF-8') ?></groundspeak:owner>
|
||||
<groundspeak:name><?= Okapi::xmlescape($c['name']) ?></groundspeak:name>
|
||||
<groundspeak:placed_by><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:placed_by>
|
||||
<groundspeak:owner id="<?= $c['owner']['uuid'] ?>"><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:owner>
|
||||
<groundspeak:type><?= $vars['cache_GPX_types'][$c['type']] ?></groundspeak:type>
|
||||
<groundspeak:container><?= $vars['cache_GPX_sizes'][$c['size2']] ?></groundspeak:container>
|
||||
<groundspeak:difficulty><?= $c['difficulty'] ?></groundspeak:difficulty>
|
||||
<groundspeak:terrain><?= $c['terrain'] ?></groundspeak:terrain>
|
||||
<groundspeak:long_description html="True">
|
||||
<p>
|
||||
<a href="<?= $c['url'] ?>"><?= htmlspecialchars($c['name'], ENT_COMPAT, 'UTF-8') ?></a>
|
||||
<?= _("hidden by") ?> <a href='<?= $c['owner']['profile_url'] ?>'><?= htmlspecialchars($c['owner']['username'], ENT_COMPAT, 'UTF-8') ?></a><br/>
|
||||
<a href="<?= $c['url'] ?>"><?= Okapi::xmlescape($c['name']) ?></a>
|
||||
<?= _("hidden by") ?> <a href='<?= $c['owner']['profile_url'] ?>'><?= Okapi::xmlescape($c['owner']['username']) ?></a><br/>
|
||||
<? if ($vars['recommendations'] == 'desc:count') { /* Does user want us to include recommendations count? */ ?>
|
||||
<?= sprintf(ngettext("%d recommendation", "%d recommendations", $c['recommendations']), $c['recommendations']) ?>
|
||||
(<?= sprintf(ngettext("found %d time", "found %d times", $c['founds']), $c['founds']) ?>).
|
||||
@@ -51,7 +55,7 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<? } ?>
|
||||
</p>
|
||||
<? if (($vars['my_notes'] == 'desc:text') && ($c['my_notes'] != null)) { /* Does user want us to include personal notes? */ ?>
|
||||
<p><b><?= _("Personal notes") ?>:</b> <?= htmlspecialchars($c['my_notes'], ENT_COMPAT, 'UTF-8') ?></p>
|
||||
<p><b><?= _("Personal notes") ?>:</b> <?= Okapi::xmlescape($c['my_notes']) ?></p>
|
||||
<? } ?>
|
||||
|
||||
<? if ($vars['attrs'] == 'desc:text' && count($c['attrnames']) > 0) { /* Does user want us to include attributes? */ ?>
|
||||
@@ -62,11 +66,11 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<p><?= _("Trackables") ?>:</p>
|
||||
<ul>
|
||||
<? foreach ($c['trackables'] as $t) { ?>
|
||||
<li><a href='<?= htmlspecialchars($t['url'], ENT_COMPAT, 'UTF-8') ?>'><?= htmlspecialchars($t['name'], ENT_COMPAT, 'UTF-8') ?></a> (<?= $t['code'] ?>)</li>
|
||||
<li><a href='<?= Okapi::xmlescape($t['url']) ?>'><?= Okapi::xmlescape($t['name']) ?></a> (<?= $t['code'] ?>)</li>
|
||||
<? } ?>
|
||||
</ul>
|
||||
<? } ?>
|
||||
<?= htmlspecialchars($c['description'], ENT_COMPAT, 'UTF-8') ?>
|
||||
<?= 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? */ ?>
|
||||
<?
|
||||
# We will split images into two subcategories: spoilers and nonspoilers.
|
||||
@@ -79,15 +83,15 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<? if (count($nonspoilers) > 0) { ?>
|
||||
<h2><?= _("Images") ?> (<?= count($nonspoilers) ?>)</h2>
|
||||
<? foreach ($nonspoilers as $img) { ?>
|
||||
<p><img src='<?= htmlspecialchars($img['url'], ENT_COMPAT, 'UTF-8') ?>'><br>
|
||||
<?= htmlspecialchars($img['caption'], ENT_COMPAT, 'UTF-8') ?></p>
|
||||
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
||||
<?= Okapi::xmlescape($img['caption']) ?></p>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? if (count($spoilers) > 0 && $vars['images'] == 'descrefs:all') { ?>
|
||||
<h2><?= _("Spoilers") ?> (<?= count($spoilers) ?>)</h2>
|
||||
<? foreach ($spoilers as $img) { ?>
|
||||
<p><img src='<?= htmlspecialchars($img['url'], ENT_COMPAT, 'UTF-8') ?>'><br>
|
||||
<?= htmlspecialchars($img['caption'], ENT_COMPAT, 'UTF-8') ?></p>
|
||||
<p><img src='<?= Okapi::xmlescape($img['url']) ?>'><br>
|
||||
<?= Okapi::xmlescape($img['caption']) ?></p>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
<? } ?>
|
||||
@@ -95,20 +99,20 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<p><?= _("Image descriptions") ?>:</p>
|
||||
<ul>
|
||||
<? foreach ($c['images'] as $no => $img) { ?>
|
||||
<li><?= $img['unique_caption'] ?>. <?= htmlspecialchars($img['caption'], ENT_COMPAT, 'UTF-8') ?></li>
|
||||
<li><?= $img['unique_caption'] ?>. <?= Okapi::xmlescape($img['caption']) ?></li>
|
||||
<? } ?>
|
||||
</ul>
|
||||
<? } ?>
|
||||
</groundspeak:long_description>
|
||||
<groundspeak:encoded_hints><?= htmlspecialchars($c['hint'], ENT_COMPAT, 'UTF-8') ?></groundspeak:encoded_hints>
|
||||
<groundspeak:encoded_hints><?= Okapi::xmlescape($c['hint']) ?></groundspeak:encoded_hints>
|
||||
<? if ($vars['latest_logs']) { /* Does user want us to include latest log entries? */ ?>
|
||||
<groundspeak:logs>
|
||||
<? foreach ($c['latest_logs'] as $log) { ?>
|
||||
<groundspeak:log id="<?= $log['uuid'] ?>">
|
||||
<groundspeak:date><?= $log['date'] ?></groundspeak:date>
|
||||
<groundspeak:type><?= $log['type'] ?></groundspeak:type>
|
||||
<groundspeak:finder id="<?= $log['user']['uuid'] ?>"><?= htmlspecialchars($log['user']['username'], ENT_COMPAT, 'UTF-8') ?></groundspeak:finder>
|
||||
<groundspeak:text encoded="False"><?= htmlspecialchars($log['comment'], ENT_COMPAT, 'UTF-8') ?></groundspeak:text>
|
||||
<groundspeak:finder id="<?= $log['user']['uuid'] ?>"><?= Okapi::xmlescape($log['user']['username']) ?></groundspeak:finder>
|
||||
<groundspeak:text encoded="False"><?= Okapi::xmlescape($log['comment']) ?></groundspeak:text>
|
||||
</groundspeak:log>
|
||||
<? } ?>
|
||||
</groundspeak:logs>
|
||||
@@ -150,11 +154,11 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<? list($lat, $lon) = explode("|", $wpt['location']); ?>
|
||||
<wpt lat="<?= $lat ?>" lon="<?= $lon ?>">
|
||||
<time><?= $c['date_created'] ?></time>
|
||||
<name><?= htmlspecialchars($wpt['name'], ENT_COMPAT, 'UTF-8') ?></name>
|
||||
<cmt><?= htmlspecialchars($wpt['description'], ENT_COMPAT, 'UTF-8') ?></cmt>
|
||||
<desc><?= htmlspecialchars($wpt['description'], ENT_COMPAT, 'UTF-8') ?></desc>
|
||||
<name><?= Okapi::xmlescape($wpt['name']) ?></name>
|
||||
<cmt><?= Okapi::xmlescape($wpt['description']) ?></cmt>
|
||||
<desc><?= Okapi::xmlescape($wpt['description']) ?></desc>
|
||||
<url><?= $c['url'] ?></url>
|
||||
<urlname><?= htmlspecialchars($c['name'], ENT_COMPAT, 'UTF-8') ?></urlname>
|
||||
<urlname><?= Okapi::xmlescape($c['name']) ?></urlname>
|
||||
<sym><?= $wpt['sym'] ?></sym>
|
||||
<type>Waypoint|<?= $wpt['sym'] ?></type>
|
||||
<? if ($vars['ns_gsak']) { ?>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for fields like
|
||||
<b>name</b> and <b>description</b>.</p>
|
||||
<p>Please note, that you may also access caches descriptions in all
|
||||
<p>Please note, that you may also access caches' descriptions in all
|
||||
available languages. If you want to do this, you should use fields
|
||||
<b>names</b>, <b>descriptions</b> (etc.) instead of <b>name</b> and
|
||||
<b>description</b> (etc.).</p>
|
||||
@@ -34,9 +34,15 @@
|
||||
<li><b>Traditional</b>,</li>
|
||||
<li><b>Multi</b>,</li>
|
||||
<li><b>Quiz</b>,</li>
|
||||
<li><b>Virtual</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>
|
||||
@@ -58,37 +64,62 @@
|
||||
<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 quering OKAPI.</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 quering OKAPI.</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 quering OKAPI.</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 directon
|
||||
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 quering OKAPI.</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 user already found this cache. See also <b>found_status</b> parameter
|
||||
of the services/caches/search/all method.</p>
|
||||
<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_not_found</b> - boolean, true if 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>
|
||||
<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>null</b></p>
|
||||
</li>
|
||||
<li><b>founds</b> - number of times the geocache was successfully found,</li>
|
||||
<li><b>notfounds</b> - number of times the geocache was not found,</li>
|
||||
<li class='deprecated'>
|
||||
<b>size</b> - deprecated
|
||||
(<a href='http://code.google.com/p/opencaching-api/issues/detail?id=155'>why?</a>),
|
||||
@@ -138,8 +169,8 @@
|
||||
following structure:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - UUID of the image,</li>
|
||||
<li><b>url</b> - an URL of the image,</li>
|
||||
<li><b>thumb_url</b> - an URL of a small (thumb) version of the image
|
||||
<li><b>url</b> - URL of the image,</li>
|
||||
<li><b>thumb_url</b> - URL of a small (thumb) version of the image
|
||||
<b>or null</b> when no thumb is available (e.g. there are no thumbs
|
||||
for spoiler images),</li>
|
||||
<li><b>caption</b> - plain-text string, caption of the image,</li>
|
||||
@@ -188,8 +219,11 @@
|
||||
<li><b>name</b> - plain-text "codename" for the waypoint (not unique),</li>
|
||||
<li><b>location</b> - location of the waypoint in the "lat|lon" format
|
||||
(<i>lat</i> and <i>lon</i> are in full degrees with a dot as a decimal point),</li>
|
||||
<li><b>sym</b> - string, one of globally-recognized waypoint symbol
|
||||
names (such as "Flag, Green" or "Parking Area"),</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>
|
||||
@@ -244,6 +278,6 @@
|
||||
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 a HTTP 400 error.</p>
|
||||
respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -30,7 +30,8 @@ class WebService
|
||||
'rating', 'rating_votes', 'recommendations', 'req_passwd', 'description',
|
||||
'descriptions', 'hint', 'hints', 'images', 'attrnames', 'latest_logs',
|
||||
'my_notes', 'trackables_count', 'trackables', 'alt_wpts', 'last_found',
|
||||
'last_modified', 'date_created', 'date_hidden', 'internal_id');
|
||||
'last_modified', 'date_created', 'date_hidden', 'internal_id', 'is_watched',
|
||||
'is_ignored', 'willattends');
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
@@ -202,8 +203,26 @@ class WebService
|
||||
break;
|
||||
case 'is_found': /* handled separately */ break;
|
||||
case 'is_not_found': /* handled separately */ break;
|
||||
case 'is_watched': /* handled separately */ break;
|
||||
case 'is_ignored': /* handled separately */ break;
|
||||
case 'founds': $entry['founds'] = $row['founds'] + 0; break;
|
||||
case 'notfounds': $entry['notfounds'] = $row['notfounds'] + 0; break;
|
||||
case 'notfounds':
|
||||
if ($row['type'] != 6) { # non-event
|
||||
$entry['notfounds'] = $row['notfounds'] + 0;
|
||||
} else { # event
|
||||
$entry['notfounds'] = 0;
|
||||
}
|
||||
break;
|
||||
case 'willattends':
|
||||
# OCPL stats count "Will attend" log entries as "notfounds"
|
||||
# (just another pecularity regarding "event caches").
|
||||
# I am not sure about OCDE branch though...
|
||||
if ($row['type'] == 6) { # event
|
||||
$entry['willattends'] = $row['notfounds'] + 0;
|
||||
} else { # non-event
|
||||
$entry['willattends'] = 0;
|
||||
}
|
||||
break;
|
||||
case 'size':
|
||||
# Deprecated. Leave it for backward-compatibility. See issue 155.
|
||||
switch (Okapi::cache_sizeid_to_size2($row['size']))
|
||||
@@ -293,8 +312,12 @@ class WebService
|
||||
cache_logs cl
|
||||
where
|
||||
c.cache_id = cl.cache_id
|
||||
and cl.type = '".mysql_real_escape_string(Okapi::logtypename2id("Found it"))."'
|
||||
and cl.type in (
|
||||
'".mysql_real_escape_string(Okapi::logtypename2id("Found it"))."',
|
||||
'".mysql_real_escape_string(Okapi::logtypename2id("Attended"))."'
|
||||
)
|
||||
and cl.user_id = '".mysql_real_escape_string($user_id)."'
|
||||
".((Settings::get('OC_BRANCH') == 'oc.pl') ? "and cl.deleted = 0" : "")."
|
||||
");
|
||||
$tmp2 = array();
|
||||
foreach ($tmp as $cache_code)
|
||||
@@ -318,6 +341,7 @@ class WebService
|
||||
c.cache_id = cl.cache_id
|
||||
and cl.type = '".mysql_real_escape_string(Okapi::logtypename2id("Didn't find it"))."'
|
||||
and cl.user_id = '".mysql_real_escape_string($user_id)."'
|
||||
".((Settings::get('OC_BRANCH') == 'oc.pl') ? "and cl.deleted = 0" : "")."
|
||||
");
|
||||
$tmp2 = array();
|
||||
foreach ($tmp as $cache_code)
|
||||
@@ -326,6 +350,50 @@ class WebService
|
||||
$result_ref['is_not_found'] = isset($tmp2[$cache_code]);
|
||||
}
|
||||
|
||||
# is_watched
|
||||
|
||||
if (in_array('is_watched', $fields))
|
||||
{
|
||||
if ($request->token == null)
|
||||
throw new BadRequest("Level 3 Authentication is required to access 'is_watched' field.");
|
||||
$tmp = Db::select_column("
|
||||
select c.wp_oc
|
||||
from
|
||||
caches c,
|
||||
cache_watches cw
|
||||
where
|
||||
c.cache_id = cw.cache_id
|
||||
and cw.user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$tmp2 = array();
|
||||
foreach ($tmp as $cache_code)
|
||||
$tmp2[$cache_code] = true;
|
||||
foreach ($results as $cache_code => &$result_ref)
|
||||
$result_ref['is_watched'] = isset($tmp2[$cache_code]);
|
||||
}
|
||||
|
||||
# is_ignored
|
||||
|
||||
if (in_array('is_ignored', $fields))
|
||||
{
|
||||
if ($request->token == null)
|
||||
throw new BadRequest("Level 3 Authentication is required to access 'is_ignored' field.");
|
||||
$tmp = Db::select_column("
|
||||
select c.wp_oc
|
||||
from
|
||||
caches c,
|
||||
cache_ignore ci
|
||||
where
|
||||
c.cache_id = ci.cache_id
|
||||
and ci.user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$tmp2 = array();
|
||||
foreach ($tmp as $cache_code)
|
||||
$tmp2[$cache_code] = true;
|
||||
foreach ($results as $cache_code => &$result_ref)
|
||||
$result_ref['is_ignored'] = isset($tmp2[$cache_code]);
|
||||
}
|
||||
|
||||
# Descriptions and hints.
|
||||
|
||||
if (in_array('description', $fields) || in_array('descriptions', $fields)
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<p>Pipe-separated list of ISO 639-1 language codes. This indicates the
|
||||
order of preference in which language will be chosen for fields like
|
||||
<b>name</b> and <b>description</b>.</p>
|
||||
<p>Please note, that you may also access caches descriptions in all
|
||||
<p>Please note, that you may also access caches' descriptions in all
|
||||
available languages. If you want to do this, you should use fields
|
||||
<b>names</b>, <b>descriptions</b> (etc.) instead of <b>name</b> and
|
||||
<b>description</b> (etc.).</p>
|
||||
@@ -40,6 +40,6 @@
|
||||
<pre>{"OP3D96": {"type": "Traditional"}, "OC124": null}</pre>
|
||||
<p>Value of <b>null</b> means that the given cache haven't been found.
|
||||
(This behavior is different than in the services/caches/geocache method, which
|
||||
responds with a HTTP 400 error in such case.)</p>
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -41,23 +41,28 @@ class ReplicateListener
|
||||
}
|
||||
}
|
||||
|
||||
public static function reset()
|
||||
public static function reset($mail_admins = true)
|
||||
{
|
||||
# This will be called when there are "too many" entries in the changelog
|
||||
# and the replicate module thinks it better to just reset the entire TileTree.
|
||||
# For the first hours after such reset maps may work very slow!
|
||||
|
||||
Okapi::mail_admins("OKAPI TileMap database reset",
|
||||
"Hello,\n\n".
|
||||
"OKAPI's 'replicate' module detected a big database update. As result\n".
|
||||
"of this, OKAPI decided to reset the TileMap cache. This may\n".
|
||||
"temporarily influence TileMap performance. The map may work much\n".
|
||||
"slower during the next few hours or days, while the cache is being\n".
|
||||
"rebuilt.\n\n".
|
||||
"If this happens frequently, please contact OKAPI developers. It may\n".
|
||||
"indicate a bug in OKAPI's 'replicate' module or cronjob settings.\n\n".
|
||||
"Thanks!"
|
||||
);
|
||||
if ($mail_admins)
|
||||
{
|
||||
Okapi::mail_admins("OKAPI TileMap database reset",
|
||||
"Hello,\n\n".
|
||||
"OKAPI's 'replicate' module detected a big database update. As result\n".
|
||||
"of this, OKAPI decided to reset the TileMap cache. This may\n".
|
||||
"temporarily influence TileMap performance. The map may work much\n".
|
||||
"slower during the next few hours or days, while the cache is being\n".
|
||||
"rebuilt.\n\n".
|
||||
"If this happens frequently, please contact OKAPI developers. It may\n".
|
||||
"indicate a bug in OKAPI's 'replicate' module or cronjob settings.\n\n".
|
||||
"Thanks!\n\n".
|
||||
"P.S. This may also happen if you didn't run OKAPI on this server\n".
|
||||
"for a while (your server was down or OKAPI didn't work properly)."
|
||||
);
|
||||
}
|
||||
Db::execute("delete from okapi_tile_status");
|
||||
Db::execute("delete from okapi_tile_caches");
|
||||
}
|
||||
|
@@ -17,13 +17,15 @@ use okapi\DoesNotExist;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use okapi\OkapiInternalConsumer;
|
||||
use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiLock;
|
||||
|
||||
use okapi\services\caches\map\TileTree;
|
||||
use okapi\services\caches\map\DefaultTileRenderer;
|
||||
|
||||
use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
require_once('tiletree.inc.php');
|
||||
require_once('tilerenderer.inc.php');
|
||||
require_once($GLOBALS['rootpath']."okapi/services/caches/search/searching.inc.php");
|
||||
|
||||
class WebService
|
||||
{
|
||||
@@ -48,7 +50,7 @@ class WebService
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
'min_auth_level' => 3
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,261 +86,96 @@ class WebService
|
||||
if ($y >= 1<<$zoom)
|
||||
throw new InvalidParam('y', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||
|
||||
# status
|
||||
# Now, we will create a search set (or use one previously created).
|
||||
# Instead of creating a new OkapiInternalRequest object, we will pass
|
||||
# the current request directly. We can do that, because we inherit all
|
||||
# of the "save" method's parameters.
|
||||
|
||||
$filter_conds = array();
|
||||
$tmp = $request->get_parameter('status');
|
||||
if ($tmp == null) $tmp = "Available";
|
||||
$allowed_status_codes = array();
|
||||
foreach (explode("|", $tmp) as $name)
|
||||
{
|
||||
try
|
||||
{
|
||||
$allowed_status_codes[] = Okapi::cache_status_name2id($name);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new InvalidParam('status', "'$name' is not a valid cache status.");
|
||||
}
|
||||
}
|
||||
sort($allowed_status_codes);
|
||||
if (count($allowed_status_codes) == 0)
|
||||
throw new InvalidParam('status');
|
||||
if (count($allowed_status_codes) < 3)
|
||||
$filter_conds[] = "status in ('".implode("','", array_map('mysql_real_escape_string', $allowed_status_codes))."')";
|
||||
$search_set = OkapiServiceRunner::call('services/caches/search/save', $request);
|
||||
$set_id = $search_set['set_id'];
|
||||
|
||||
# type
|
||||
# Get caches which are present in the result set AND within the tile
|
||||
# (+ those around the borders).
|
||||
|
||||
if ($tmp = $request->get_parameter('type'))
|
||||
{
|
||||
$operator = "in";
|
||||
if ($tmp[0] == '-')
|
||||
{
|
||||
$tmp = substr($tmp, 1);
|
||||
$operator = "not in";
|
||||
}
|
||||
$types = array();
|
||||
foreach (explode("|", $tmp) as $name)
|
||||
{
|
||||
try
|
||||
{
|
||||
$id = Okapi::cache_type_name2id($name);
|
||||
$types[] = $id;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new InvalidParam('type', "'$name' is not a valid cache type.");
|
||||
}
|
||||
}
|
||||
sort($types);
|
||||
|
||||
# Check if all cache types were selected. Since we're running
|
||||
# on various OC installations, we don't know which caches types
|
||||
# are "all" here. We have to check.
|
||||
|
||||
$all = self::$USE_OTHER_CACHE ? Cache::get('all_cache_types') : null;
|
||||
if ($all === null)
|
||||
{
|
||||
$all = Db::select_column("
|
||||
select distinct type
|
||||
from caches
|
||||
where status in (1,2,3)
|
||||
");
|
||||
Cache::set('all_cache_types', $all, 86400);
|
||||
}
|
||||
$all_included = true;
|
||||
foreach ($all as $type)
|
||||
if (!in_array($type, $types))
|
||||
{
|
||||
$all_included = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($all_included && ($operator == "in"))
|
||||
{
|
||||
# All cache types are to be included. This is common.
|
||||
}
|
||||
else
|
||||
{
|
||||
$filter_conds[] = "type $operator ('".implode("','", array_map('mysql_real_escape_string', $types))."')";
|
||||
}
|
||||
}
|
||||
|
||||
# User-specific geocaches (cached together).
|
||||
|
||||
$cache_key = "tileuser/".$request->token->user_id;
|
||||
$user = self::$USE_OTHER_CACHE ? Cache::get($cache_key) : null;
|
||||
if ($user === null)
|
||||
{
|
||||
$user = array();
|
||||
|
||||
# Ignored caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select cache_id
|
||||
from cache_ignore
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$user['ignored'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['ignored'][$cache_id] = true;
|
||||
|
||||
# Found caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from cache_logs
|
||||
where
|
||||
user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
and type = 1
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
");
|
||||
$user['found'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['found'][$cache_id] = true;
|
||||
|
||||
# Own caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from caches
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$user['own'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['own'][$cache_id] = true;
|
||||
|
||||
Cache::set($cache_key, $user, 30);
|
||||
}
|
||||
|
||||
# exclude_ignored
|
||||
|
||||
$tmp = $request->get_parameter('exclude_ignored');
|
||||
if ($tmp === null) $tmp = "false";
|
||||
if (!in_array($tmp, array('true', 'false'), true))
|
||||
throw new InvalidParam('exclude_ignored', "'$tmp'");
|
||||
if ($tmp == 'true')
|
||||
{
|
||||
$excluded_dict = $user['ignored'];
|
||||
} else {
|
||||
$excluded_dict = array();
|
||||
}
|
||||
|
||||
# exclude_my_own
|
||||
|
||||
if ($tmp = $request->get_parameter('exclude_my_own'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false'), 1))
|
||||
throw new InvalidParam('exclude_my_own', "'$tmp'");
|
||||
if (($tmp == 'true') && (count($user['own']) > 0))
|
||||
{
|
||||
foreach ($user['own'] as $cache_id => $v)
|
||||
$excluded_dict[$cache_id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
# found_status
|
||||
|
||||
if ($tmp = $request->get_parameter('found_status'))
|
||||
{
|
||||
if (!in_array($tmp, array('found_only', 'notfound_only', 'either')))
|
||||
throw new InvalidParam('found_status', "'$tmp'");
|
||||
if ($tmp == 'either') {
|
||||
# Do nothing.
|
||||
} elseif ($tmp == 'notfound_only') {
|
||||
# Easy.
|
||||
foreach ($user['found'] as $cache_id => $v)
|
||||
$excluded_dict[$cache_id] = true;
|
||||
} else {
|
||||
# Found only. This will slow down queries somewhat. But it is rare.
|
||||
$filter_conds[] = "cache_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($user['found'])))."')";
|
||||
}
|
||||
}
|
||||
|
||||
# with_trackables_only
|
||||
|
||||
if ($tmp = $request->get_parameter('with_trackables_only'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false'), 1))
|
||||
throw new InvalidParam('with_trackables_only', "'$tmp'");
|
||||
if ($tmp == 'true')
|
||||
{
|
||||
$filter_conds[] = "flags & ".TileTree::$FLAG_HAS_TRACKABLES;
|
||||
}
|
||||
}
|
||||
|
||||
# not_yet_found_only
|
||||
|
||||
if ($tmp = $request->get_parameter('not_yet_found_only')) # ftf hunter
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false'), 1))
|
||||
throw new InvalidParam('not_yet_found_only', "'$tmp'");
|
||||
if ($tmp == 'true')
|
||||
{
|
||||
$filter_conds[] = "flags & ".TileTree::$FLAG_NOT_YET_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
# rating
|
||||
|
||||
if ($tmp = $request->get_parameter('rating'))
|
||||
{
|
||||
if (!preg_match("/^[1-5]-[1-5](\|X)?$/", $tmp))
|
||||
throw new InvalidParam('rating', "'$tmp'");
|
||||
list($min, $max) = explode("-", $tmp);
|
||||
if (strpos($max, "|X") !== false)
|
||||
{
|
||||
$max = $max[0];
|
||||
$allow_null = true;
|
||||
} else {
|
||||
$allow_null = false;
|
||||
}
|
||||
if ($min > $max)
|
||||
throw new InvalidParam('rating', "'$tmp'");
|
||||
if (($min == 1) && ($max == 5) && $allow_null) {
|
||||
/* no extra condition necessary */
|
||||
} else {
|
||||
$filter_conds[] = "(rating between $min and $max)".
|
||||
($allow_null ? " or rating is null" : "");
|
||||
}
|
||||
}
|
||||
|
||||
# Filter out caches in $excluded_dict.
|
||||
|
||||
if (count($excluded_dict) > 0)
|
||||
{
|
||||
$filter_conds[] = "cache_id not in ('".implode("','", array_keys($excluded_dict))."')";
|
||||
}
|
||||
|
||||
# Get caches within the tile (+ those around the borders). All filtering
|
||||
# options need to be applied here.
|
||||
|
||||
$rs = TileTree::query_fast($zoom, $x, $y, $filter_conds);
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointA", null,
|
||||
microtime(true) - $checkpointA_started);
|
||||
$checkpointB_started = microtime(true);
|
||||
|
||||
# Read the rows and add extra flags to them.
|
||||
|
||||
$rs = TileTree::query_fast($zoom, $x, $y, $set_id);
|
||||
$rows = array();
|
||||
if ($rs !== null)
|
||||
{
|
||||
while ($row = mysql_fetch_row($rs))
|
||||
{
|
||||
# Add the "found" flag, to indicate that this cache needs
|
||||
# to be drawn as found.
|
||||
|
||||
if (isset($user['found'][$row[0]]))
|
||||
$row[6] |= TileTree::$FLAG_FOUND; # $row[6] is "flags"
|
||||
if (isset($user['own'][$row[0]]))
|
||||
$row[6] |= TileTree::$FLAG_OWN; # $row[6] is "flags"
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
unset($row);
|
||||
}
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointA", null,
|
||||
microtime(true) - $checkpointA_started);
|
||||
$checkpointB_started = microtime(true);
|
||||
|
||||
# Compute a fast image fingerprint. This will be used both for ETags
|
||||
# Add dynamic, user-related flags.
|
||||
|
||||
if (count($rows) > 0)
|
||||
{
|
||||
# Load user-related cache ids.
|
||||
|
||||
$cache_key = "tileuser/".$request->token->user_id;
|
||||
$user = self::$USE_OTHER_CACHE ? Cache::get($cache_key) : null;
|
||||
if ($user === null)
|
||||
{
|
||||
$user = array();
|
||||
|
||||
# Ignored caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select cache_id
|
||||
from cache_ignore
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$user['ignored'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['ignored'][$cache_id] = true;
|
||||
|
||||
# Found caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from cache_logs
|
||||
where
|
||||
user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
and type = 1
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
");
|
||||
$user['found'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['found'][$cache_id] = true;
|
||||
|
||||
# Own caches.
|
||||
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from caches
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$user['own'] = array();
|
||||
while (list($cache_id) = mysql_fetch_row($rs))
|
||||
$user['own'][$cache_id] = true;
|
||||
|
||||
Cache::set($cache_key, $user, 30);
|
||||
}
|
||||
|
||||
# Add extra flags to geocaches.
|
||||
|
||||
foreach ($rows as &$row_ref)
|
||||
{
|
||||
# Add the "found" flag (to indicate that this cache needs
|
||||
# to be drawn as found) and the "own" flag (to indicate that
|
||||
# the current user is the owner).
|
||||
|
||||
if (isset($user['found'][$row_ref[0]]))
|
||||
$row_ref[6] |= TileTree::$FLAG_FOUND; # $row[6] is "flags"
|
||||
if (isset($user['own'][$row_ref[0]]))
|
||||
$row_ref[6] |= TileTree::$FLAG_OWN; # $row[6] is "flags"
|
||||
}
|
||||
}
|
||||
|
||||
# Compute the image hash/fingerprint. This will be used both for ETags
|
||||
# and internal cache ($cache_key).
|
||||
|
||||
$tile = new DefaultTileRenderer($zoom, $rows);
|
||||
|
@@ -11,14 +11,7 @@
|
||||
<req name='z'>Zoom level (0..21).</req>
|
||||
<req name='x'>Tile number on the X axis.</req>
|
||||
<req name='y'>Tile number on the Y axis.</req>
|
||||
<opt name='with_trackables_only' default='false'>
|
||||
All geocaches without trackables will be skipped.
|
||||
</opt>
|
||||
<opt name='not_yet_found_only' default='false'>
|
||||
All geocaches which have been already found by someone, will be skipped.
|
||||
</opt>
|
||||
<import-params method="services/caches/search/all"
|
||||
params="status|type|exclude_ignored|exclude_my_own|found_status|rating"/>
|
||||
<import-params method="services/caches/search/save"/>
|
||||
<returns>
|
||||
The PNG image with the requested map tile.
|
||||
</returns>
|
||||
|
@@ -34,7 +34,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
* Changing this will affect all generated hashes. You should increment it
|
||||
* whenever you alter anything in the drawing algorithm.
|
||||
*/
|
||||
private static $VERSION = 41;
|
||||
private static $VERSION = 56;
|
||||
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
@@ -121,12 +121,20 @@ class DefaultTileRenderer implements TileRenderer
|
||||
{
|
||||
# Miss. Check default cache. WRTODO: upgrade to normal Cache?
|
||||
|
||||
$cache_key = "tilesrc/".Okapi::$revision."/".self::$VERSION."/".$key;
|
||||
$gd2_path = self::$USE_STATIC_IMAGE_CACHE
|
||||
? FileCache::get_file_path($cache_key) : null;
|
||||
if ($gd2_path === null)
|
||||
try
|
||||
{
|
||||
# Miss again. Read the image from PNG.
|
||||
$cache_key = "tilesrc/".Okapi::$revision."/".self::$VERSION."/".$key;
|
||||
$gd2_path = self::$USE_STATIC_IMAGE_CACHE
|
||||
? FileCache::get_file_path($cache_key) : null;
|
||||
if ($gd2_path === null)
|
||||
throw new Exception("Not in cache");
|
||||
# File cache hit. GD2 files are much faster to read than PNGs.
|
||||
# This can throw an Exception (see bug#160).
|
||||
$locmem_cache[$key] = imagecreatefromgd2($gd2_path);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# Miss again (or error decoding). Read the image from PNG.
|
||||
|
||||
$locmem_cache[$key] = imagecreatefrompng($GLOBALS['rootpath']."okapi/static/tilemap/$name.png");
|
||||
|
||||
@@ -151,11 +159,6 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$gd2 = ob_get_clean();
|
||||
FileCache::set($cache_key, $gd2);
|
||||
}
|
||||
else
|
||||
{
|
||||
# File cache hit. GD2 files are much faster to read than PNGs.
|
||||
$locmem_cache[$key] = imagecreatefromgd2($gd2_path);
|
||||
}
|
||||
}
|
||||
return $locmem_cache[$key];
|
||||
}
|
||||
@@ -185,9 +188,10 @@ class DefaultTileRenderer implements TileRenderer
|
||||
|
||||
private function draw_cache(&$cache_struct)
|
||||
{
|
||||
if ($this->zoom <= 8)
|
||||
$capt = ($cache_struct[6] & TileTree::$FLAG_DRAW_CAPTION);
|
||||
if (($this->zoom <= 8) && (!$capt))
|
||||
$this->draw_cache_tiny($cache_struct);
|
||||
elseif ($this->zoom <= 12)
|
||||
elseif (($this->zoom <= 12) && (!$capt))
|
||||
$this->draw_cache_medium($cache_struct);
|
||||
else
|
||||
$this->draw_cache_large($cache_struct);
|
||||
@@ -219,7 +223,8 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$r = 0; $g = 0; $b = 0;
|
||||
} elseif ($found) {
|
||||
$key = 'large_outer_found';
|
||||
$a = 1; $br = 40; $c = 20;
|
||||
$a = ($flags & TileTree::$FLAG_DRAW_CAPTION) ? .7 : .35;
|
||||
$br = 40; $c = 20;
|
||||
//$a = 0.5; $br = 0; $c = 0;
|
||||
$r = 0; $g = 0; $b = 0;
|
||||
} elseif ($new) {
|
||||
@@ -289,7 +294,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
|
||||
if ($found)
|
||||
{
|
||||
$icon = self::get_image("found", 0.7, $br, $c, $r, $g, $b);
|
||||
$icon = self::get_image("found", 0.7*$a, $br, $c, $r, $g, $b);
|
||||
imagecopy($this->im, $icon, $px - 2, $py - $center_y - 3, 0, 0, 16, 16);
|
||||
}
|
||||
|
||||
@@ -428,10 +433,14 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$found = $flags & TileTree::$FLAG_FOUND;
|
||||
$own = $flags & TileTree::$FLAG_OWN;
|
||||
$new = $flags & TileTree::$FLAG_NEW;
|
||||
if ($found && (!($flags & TileTree::$FLAG_DRAW_CAPTION)))
|
||||
$a = .35;
|
||||
else
|
||||
$a = 1;
|
||||
|
||||
# Put the marker (indicates the type).
|
||||
|
||||
$marker = self::get_image("medium_".self::get_type_suffix($type, false));
|
||||
$marker = self::get_image("medium_".self::get_type_suffix($type, false), $a);
|
||||
$width = 14;
|
||||
$height = 14;
|
||||
$center_x = 7;
|
||||
@@ -459,6 +468,24 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$py - ($center_y - $markercenter_y) - 8, 0, 0, 16, 16);
|
||||
}
|
||||
|
||||
# Put small versions of rating icons.
|
||||
|
||||
if ($status == 1)
|
||||
{
|
||||
if ($rating >= 4.2)
|
||||
{
|
||||
if ($flags & TileTree::$FLAG_STAR) {
|
||||
$icon = self::get_image("rating_grin_small", max(0.6, $a));
|
||||
imagecopy($this->im, $icon, $px - 5, $py - $center_y - 1, 0, 0, 6, 6);
|
||||
$icon = self::get_image("rating_star_small", max(0.6, $a));
|
||||
imagecopy($this->im, $icon, $px - 2, $py - $center_y - 3, 0, 0, 10, 10);
|
||||
} else {
|
||||
$icon = self::get_image("rating_grin_small", max(0.6, $a));
|
||||
imagecopy($this->im, $icon, $px - 3, $py - $center_y - 1, 0, 0, 6, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($own)
|
||||
{
|
||||
# Mark own caches with additional overlay.
|
||||
@@ -470,7 +497,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
{
|
||||
# Mark found caches with V.
|
||||
|
||||
$icon = self::get_image("found", 0.7);
|
||||
$icon = self::get_image("found", 0.7*$a);
|
||||
imagecopy($this->im, $icon, $px - ($center_x - $markercenter_x) - 7,
|
||||
$py - ($center_y - $markercenter_y) - 9, 0, 0, 16, 16);
|
||||
}
|
||||
|
@@ -46,9 +46,10 @@ class TileTree
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return MySQL's result set iterator over all caches matched by your query.
|
||||
* Return MySQL's result set iterator over all caches which are present
|
||||
* in the given result set AND in the given tile.
|
||||
*
|
||||
* Each row is an array of the following format:
|
||||
* list(cache_id, $pixel_x, $pixel_y, status, type, rating, flags, count).
|
||||
@@ -57,10 +58,8 @@ class TileTree
|
||||
* Count is the number of other caches "eclipsed" by this geocache (such
|
||||
* eclipsed geocaches are not included in the result).
|
||||
*/
|
||||
public static function query_fast($zoom, $x, $y, $filter_conds)
|
||||
public static function query_fast($zoom, $x, $y, $set_id)
|
||||
{
|
||||
$time_started = microtime(true);
|
||||
|
||||
# First, we check if the cache-set for this tile was already computed
|
||||
# (and if it was, was it empty).
|
||||
|
||||
@@ -68,16 +67,9 @@ class TileTree
|
||||
if ($status === null) # Not yet computed.
|
||||
{
|
||||
# Note, that computing the tile does not involve taking any
|
||||
# filtering parameters.
|
||||
# search parameters.
|
||||
|
||||
$status = self::compute_tile($zoom, $x, $y);
|
||||
OkapiServiceRunner::save_stats_extra("tiletree/query_fast/preparetile-miss",
|
||||
null, microtime(true) - $time_started);
|
||||
}
|
||||
else
|
||||
{
|
||||
OkapiServiceRunner::save_stats_extra("tiletree/query_fast/preparetile-hit",
|
||||
null, microtime(true) - $time_started);
|
||||
}
|
||||
|
||||
if ($status === 1) # Computed and empty.
|
||||
@@ -87,26 +79,25 @@ class TileTree
|
||||
}
|
||||
|
||||
# If we got here, then the tile is computed and not empty (status 2).
|
||||
# Since all search parameters are aggregated, we just need a simple
|
||||
# SQL query to get the filtered result.
|
||||
|
||||
$tile_upper_x = $x << 8;
|
||||
$tile_leftmost_y = $y << 8;
|
||||
|
||||
if (count($filter_conds) == 0)
|
||||
$filter_conds[] = "true";
|
||||
return Db::query("
|
||||
select
|
||||
cache_id,
|
||||
cast(z21x >> (21 - $zoom) as signed) - $tile_upper_x as px,
|
||||
cast(z21y >> (21 - $zoom) as signed) - $tile_leftmost_y as py,
|
||||
status, type, rating, flags, count(*)
|
||||
from okapi_tile_caches
|
||||
otc.cache_id,
|
||||
cast(otc.z21x >> (21 - $zoom) as signed) - $tile_upper_x as px,
|
||||
cast(otc.z21y >> (21 - $zoom) as signed) - $tile_leftmost_y as py,
|
||||
otc.status, otc.type, otc.rating, otc.flags, count(*)
|
||||
from
|
||||
okapi_tile_caches otc,
|
||||
okapi_search_results osr
|
||||
where
|
||||
z = '".mysql_real_escape_string($zoom)."'
|
||||
and x = '".mysql_real_escape_string($x)."'
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
and (".implode(") and (", $filter_conds).")
|
||||
and otc.cache_id = osr.cache_id
|
||||
and osr.set_id = '".mysql_real_escape_string($set_id)."'
|
||||
group by
|
||||
z21x >> (3 + (21 - $zoom)),
|
||||
z21y >> (3 + (21 - $zoom))
|
||||
@@ -176,9 +167,6 @@ class TileTree
|
||||
");
|
||||
}
|
||||
$status = 2;
|
||||
|
||||
OkapiServiceRunner::save_stats_extra("tiletree/compute_tile/rebuild-0",
|
||||
null, microtime(true) - $time_started);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -193,13 +181,6 @@ class TileTree
|
||||
{
|
||||
$time_started = microtime(true);
|
||||
$status = self::compute_tile($parent_zoom, $parent_x, $parent_y);
|
||||
OkapiServiceRunner::save_stats_extra("tiletree/compute_tile/build",
|
||||
null, microtime(true) - $time_started);
|
||||
}
|
||||
else
|
||||
{
|
||||
OkapiServiceRunner::save_stats_extra("tiletree/compute_tile/hit",
|
||||
null, microtime(true) - $time_started);
|
||||
}
|
||||
|
||||
if ($status === 1) # Computed and empty.
|
||||
|
90
htdocs/okapi/services/caches/mark.php
Normal file
90
htdocs/okapi/services/caches/mark.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace okapi\services\caches\mark;
|
||||
|
||||
use Exception;
|
||||
use okapi\Okapi;
|
||||
use okapi\Db;
|
||||
use okapi\OkapiRequest;
|
||||
use okapi\ParamMissing;
|
||||
use okapi\InvalidParam;
|
||||
use okapi\BadRequest;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiAccessToken;
|
||||
use okapi\Settings;
|
||||
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 3
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# User is already verified (via OAuth), but we need to verify the
|
||||
# cache code (check if it exists). We will simply call a geocache method
|
||||
# on it - this will also throw a proper exception if it doesn't exist.
|
||||
|
||||
$cache_code = $request->get_parameter('cache_code');
|
||||
if ($cache_code == null)
|
||||
throw new ParamMissing('cache_code');
|
||||
$geocache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
||||
|
||||
# watched
|
||||
|
||||
if ($tmp = $request->get_parameter('watched'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
||||
throw new InvalidParam('watched', $tmp);
|
||||
if ($tmp == 'true')
|
||||
Db::execute("
|
||||
insert ignore into cache_watches (cache_id, user_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($geocache['internal_id'])."',
|
||||
'".mysql_real_escape_string($request->token->user_id)."'
|
||||
);
|
||||
");
|
||||
elseif ($tmp == 'false')
|
||||
Db::execute("
|
||||
delete from cache_watches
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
||||
and user_id = '".mysql_real_escape_string($request->token->user_id)."';
|
||||
");
|
||||
}
|
||||
|
||||
# ignored
|
||||
|
||||
if ($tmp = $request->get_parameter('ignored'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false', 'unchanged')))
|
||||
throw new InvalidParam('ignored', $tmp);
|
||||
if ($tmp == 'true')
|
||||
Db::execute("
|
||||
insert ignore into cache_ignore (cache_id, user_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($geocache['internal_id'])."',
|
||||
'".mysql_real_escape_string($request->token->user_id)."'
|
||||
);
|
||||
");
|
||||
elseif ($tmp == 'false')
|
||||
Db::execute("
|
||||
delete from cache_ignore
|
||||
where
|
||||
cache_id = '".mysql_real_escape_string($geocache['internal_id'])."'
|
||||
and user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'success' => true,
|
||||
);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
33
htdocs/okapi/services/caches/mark.xml
Normal file
33
htdocs/okapi/services/caches/mark.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<xml>
|
||||
<brief>Mark cache as watched or ignored</brief>
|
||||
<issue-id>166</issue-id>
|
||||
<desc>
|
||||
<p>This method allows your users to mark the geocache as <b>watched</b> or
|
||||
<b>ignored</b>, or to do modify user's personal <b>notes</b> saved along the geocache.
|
||||
Read the docs on separate parameters for details.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>
|
||||
<p>Code of the geocache.</p>
|
||||
</req>
|
||||
<opt name='watched' default='unchanged'>
|
||||
<p>Mark (or unmark) the cache as watched. This should be <b>true</b>,
|
||||
<b>false</b> or <b>unchanged</b>. You may access the current state of this
|
||||
flag with the <b>is_watched</b> field of the geocache method.</p>
|
||||
</opt>
|
||||
<opt name='ignored' default='unchanged'>
|
||||
<p>Mark (or unmark) the cache as ignored. This should be <b>true</b>,
|
||||
<b>false</b> or <b>unchanged</b>. You may access the current state of this
|
||||
flag with the <b>is_ignored</b> field of the geocache method.</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>success</b> - true, if all went well.</li>
|
||||
</ul>
|
||||
<p>Please note, that currently this will <b>always</b> be true! Nothing can go
|
||||
wrong as long as you pass your parameters in a right way (and if you don't,
|
||||
you will get an HTTP 400 response). If you have received an HTTP 200 response,
|
||||
then you may assume that all went well.</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -131,6 +131,13 @@
|
||||
<p>User UUID. If given, the response will only include geocaches not found by
|
||||
the given user.</p>
|
||||
</opt>
|
||||
<opt name='watched_only' default='false'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed with an Access Token
|
||||
(you will need to use <b>Level 3</b> Authentication).</p>
|
||||
<p>Boolean. If set to <b>true</b>, only caches which the user has marked as watched
|
||||
will be included in the result. This might be used to temporarily mark geocaches
|
||||
of particular interest (e.g. "all the caches I plan to find today").</p>
|
||||
</opt>
|
||||
<opt name='exclude_ignored' default='false'>
|
||||
<p><b>Notice:</b> This parameter may be used only for requests signed
|
||||
with an Access Token (you will need to use <b>Level 3</b> Authentication).</p>
|
||||
@@ -144,6 +151,22 @@
|
||||
<p>Boolean. If set to <b>true</b>, caches which the user is an owner of will
|
||||
not be included in the result.</p>
|
||||
</opt>
|
||||
<opt name='with_trackables_only' default='false'>
|
||||
Boolean. If set to <b>true</b>, only caches with at least one trackable
|
||||
will be included in the result.
|
||||
</opt>
|
||||
<opt name='ftf_hunter' default='false'>
|
||||
Boolean. If set to <b>true</b>, only caches which have not yet been
|
||||
found <b>by anyone</b> will be included.
|
||||
</opt>
|
||||
<opt name='set_and'>
|
||||
<p>ID of a set previously created with the <b>search/save</b> method.
|
||||
If given, the results are <a href='http://en.wikipedia.org/wiki/Logical_conjunction'>AND</a>ed
|
||||
together with this set.</p>
|
||||
<p>If you want to list the set contents only, please note the default
|
||||
value of the <b>status</b> parameter! You may want to override it
|
||||
in order to include unavailable and/or archived geocaches within the set.</p>
|
||||
</opt>
|
||||
<opt name='limit' default='100'>
|
||||
<p>Integer in range 1..500. Maximum number of cache codes returned.</p>
|
||||
</opt>
|
||||
|
177
htdocs/okapi/services/caches/search/save.php
Normal file
177
htdocs/okapi/services/caches/search/save.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace okapi\services\caches\search\save;
|
||||
|
||||
require_once('searching.inc.php');
|
||||
|
||||
use okapi\Okapi;
|
||||
use okapi\OkapiRequest;
|
||||
use okapi\ParamMissing;
|
||||
use okapi\InvalidParam;
|
||||
use okapi\Db;
|
||||
use okapi\OkapiLock;
|
||||
use okapi\services\caches\search\SearchAssistant;
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get [set_id, date_created, expires] for the given params_hash
|
||||
* (or [null, null, null] if not found).
|
||||
*/
|
||||
private static function find_param_set($params_hash, $ref_max_age)
|
||||
{
|
||||
$tmp = Db::select_row("
|
||||
select
|
||||
id as id,
|
||||
unix_timestamp(date_created) as date_created,
|
||||
unix_timestamp(expires) as expires
|
||||
from okapi_search_sets
|
||||
where
|
||||
params_hash = '".mysql_real_escape_string($params_hash)."'
|
||||
and date_add(date_created, interval '".mysql_real_escape_string($ref_max_age)."' second) > now()
|
||||
order by id desc
|
||||
limit 1
|
||||
");
|
||||
if ($tmp === null)
|
||||
return array(null, null, null);
|
||||
return array($tmp['id'], $tmp['date_created'], $tmp['expires']);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# "Cache control" parameters.
|
||||
|
||||
$tmp = $request->get_parameter('min_store');
|
||||
if ($tmp === null) $tmp = "300";
|
||||
$min_store = intval($tmp);
|
||||
if (("$min_store" !== $tmp) ||($min_store < 0) || ($min_store > 64800))
|
||||
throw new InvalidParam('min_store', "Has to be in the 0..64800 range.");
|
||||
|
||||
$tmp = $request->get_parameter('ref_max_age');
|
||||
if ($tmp === null) $tmp = "300";
|
||||
if ($tmp == "nolimit") $tmp = "9999999";
|
||||
$ref_max_age = intval($tmp);
|
||||
if (("$ref_max_age" !== $tmp) || ($ref_max_age < 300))
|
||||
throw new InvalidParam('ref_max_age', "Has to be >=300.");
|
||||
|
||||
# Search params.
|
||||
|
||||
$search_params = SearchAssistant::get_common_search_params($request);
|
||||
$tables = array_merge(
|
||||
array('caches'),
|
||||
$search_params['extra_tables']
|
||||
);
|
||||
$where_conds = array_merge(
|
||||
array('caches.wp_oc is not null'),
|
||||
$search_params['where_conds']
|
||||
);
|
||||
unset($search_params);
|
||||
|
||||
# Generate, or retrieve an existing set, and return the result.
|
||||
|
||||
$result = self::get_set($tables, $where_conds, $min_store, $ref_max_age);
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
|
||||
public static function get_set($tables, $where_conds, $min_store, $ref_max_age)
|
||||
{
|
||||
# Compute the "params hash".
|
||||
|
||||
$params_hash = md5(serialize(array($tables, $where_conds)));
|
||||
|
||||
# Check if there exists an entry for this hash, which also meets the
|
||||
# given freshness criteria.
|
||||
|
||||
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
||||
if ($set_id === null)
|
||||
{
|
||||
# To avoid generating the same results by multiple threads at once
|
||||
# (the "tile" method uses the "save" method, so the problem is
|
||||
# quite real!), we will acquire a write-lock here.
|
||||
|
||||
$lock = OkapiLock::get("search-results-writer");
|
||||
$lock->acquire();
|
||||
|
||||
try
|
||||
{
|
||||
# Make sure we were the first to acquire the lock.
|
||||
|
||||
list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age);
|
||||
if ($set_id === null)
|
||||
{
|
||||
# We are in the first thread which have acquired the lock.
|
||||
# We will proceed with result-set creation. Other threads
|
||||
# will be waiting until we finish.
|
||||
|
||||
Db::execute("
|
||||
insert into okapi_search_sets (params_hash, date_created, expires)
|
||||
values (
|
||||
'processing in progress',
|
||||
now(),
|
||||
date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
||||
)
|
||||
");
|
||||
$set_id = Db::last_insert_id();
|
||||
$date_created = time();
|
||||
$expires = $date_created + $min_store + 60;
|
||||
Db::execute("
|
||||
insert into okapi_search_results (set_id, cache_id)
|
||||
select distinct
|
||||
'".mysql_real_escape_string($set_id)."',
|
||||
caches.cache_id
|
||||
from ".implode(", ", $tables)."
|
||||
where (".implode(") and (", $where_conds).")
|
||||
");
|
||||
|
||||
# Lock barrier, to make sure the data is visible by other
|
||||
# sessions. See http://bugs.mysql.com/bug.php?id=36618
|
||||
|
||||
Db::execute("lock table okapi_search_results write");
|
||||
Db::execute("unlock tables");
|
||||
|
||||
Db::execute("
|
||||
update okapi_search_sets
|
||||
set params_hash = '".mysql_real_escape_string($params_hash)."'
|
||||
where id = '".mysql_real_escape_string($set_id)."'
|
||||
");
|
||||
} else {
|
||||
# Some other thread acquired the lock before us and it has
|
||||
# generated the result set. We don't need to do anything.
|
||||
}
|
||||
$lock->release();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# SQL error? Make sure the lock is released and rethrow.
|
||||
|
||||
$lock->release();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
# If we got an old set, we may need to expand its lifetime in order to
|
||||
# meet user's "min_store" criterium.
|
||||
|
||||
if (time() + $min_store > $expires)
|
||||
{
|
||||
Db::execute("
|
||||
update okapi_search_sets
|
||||
set expires = date_add(now(), interval '".mysql_real_escape_string($min_store + 60)."' second)
|
||||
where id = '".mysql_real_escape_string($set_id)."'
|
||||
");
|
||||
}
|
||||
|
||||
return array(
|
||||
'set_id' => "$set_id",
|
||||
'generated_at' => date('c', $date_created),
|
||||
'expires' => date('c', $expires),
|
||||
);
|
||||
}
|
||||
}
|
36
htdocs/okapi/services/caches/search/save.xml
Normal file
36
htdocs/okapi/services/caches/search/save.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<xml>
|
||||
<brief>Save a search result set</brief>
|
||||
<issue-id>163</issue-id>
|
||||
<desc>
|
||||
<p>This works similar to the <b>search/all</b> method, but the returned
|
||||
set of geocaches is temporarilly stored, instead of being directly
|
||||
returned to you.</p>
|
||||
<p>You may want to use this method when you don't want your search
|
||||
results modified while the user is browsing through them, page by page.
|
||||
To view a portion of a saved search, use the <b>search/all</b>
|
||||
method with proper <b>set_and</b> <u>and <b>status</b></u> (!)
|
||||
parameters.</p>
|
||||
</desc>
|
||||
<opt name='min_store' default="300">
|
||||
The amount of time (in seconds) after which you allow OKAPI to delete
|
||||
the set (OKAPI <b>may</b> remove it, but doesn't have to).
|
||||
The maximum allowed value is 64800 (18 hours).
|
||||
</opt>
|
||||
<opt name='ref_max_age' default="300">
|
||||
<p>If OKAPI finds an existing result set which was created for your
|
||||
search query, it may return the ID of this existing set (and possibly
|
||||
extend its lifetime so it fits your <b>min_store</b>). What is the
|
||||
maximum age of the existing result set which you are willing to accept?</p>
|
||||
<p>This should be an integer (in seconds) <b>or</b> a special
|
||||
<b>nolimit</b> value. It must be greater or equal to 300 (5 minutes).</p>
|
||||
</opt>
|
||||
<import-params method='services/caches/search/all' except="offset|limit|order_by"/>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>set_id</b> - string, the identifier of your saved set,
|
||||
for future reference.</li>
|
||||
</ul>
|
||||
</returns>
|
||||
</xml>
|
@@ -232,10 +232,10 @@ class SearchAssistant
|
||||
if (($min == 1) && ($max == 5) && $allow_null) {
|
||||
/* no extra condition necessary */
|
||||
} else {
|
||||
$divisors = array(-3.0, -1.0, 0.1, 1.4, 2.2, 3.0);
|
||||
$divisors = array(-999, -1.0, 0.1, 1.4, 2.2, 999);
|
||||
$min = $divisors[$min - 1];
|
||||
$max = $divisors[$max];
|
||||
$where_conds[] = "(($X_SCORE between $min and $max) and ($X_VOTES >= 3))".
|
||||
$where_conds[] = "($X_SCORE >= $min and $X_SCORE < $max and $X_VOTES >= 3)".
|
||||
($allow_null ? " or ($X_VOTES < 3)" : "");
|
||||
}
|
||||
}
|
||||
@@ -356,6 +356,27 @@ class SearchAssistant
|
||||
$where_conds[] = "caches.cache_id not in ('".implode("','", array_map('mysql_real_escape_string', $found_cache_ids))."')";
|
||||
}
|
||||
|
||||
#
|
||||
# watched_only
|
||||
#
|
||||
|
||||
if ($tmp = $request->get_parameter('watched_only'))
|
||||
{
|
||||
if ($request->token == null)
|
||||
throw new InvalidParam('watched_only', "Might be used only for requests signed with an Access Token.");
|
||||
if (!in_array($tmp, array('true', 'false')))
|
||||
throw new InvalidParam('watched_only', "'$tmp'");
|
||||
if ($tmp == 'true')
|
||||
{
|
||||
$watched_cache_ids = Db::select_column("
|
||||
select cache_id
|
||||
from cache_watches
|
||||
where user_id = '".mysql_real_escape_string($request->token->user_id)."'
|
||||
");
|
||||
$where_conds[] = "cache_id in ('".implode("','", array_map('mysql_real_escape_string', $watched_cache_ids))."')";
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# exclude_ignored
|
||||
#
|
||||
@@ -405,6 +426,59 @@ class SearchAssistant
|
||||
$where_conds[] = "caches.name LIKE '".mysql_real_escape_string($tmp)."'";
|
||||
}
|
||||
|
||||
#
|
||||
# with_trackables_only
|
||||
#
|
||||
|
||||
if ($tmp = $request->get_parameter('with_trackables_only'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false'), 1))
|
||||
throw new InvalidParam('with_trackables_only', "'$tmp'");
|
||||
if ($tmp == 'true')
|
||||
{
|
||||
$where_conds[] = "
|
||||
caches.wp_oc in (
|
||||
select distinct wp
|
||||
from gk_item_waypoint
|
||||
)
|
||||
";
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# ftf_hunter
|
||||
#
|
||||
|
||||
if ($tmp = $request->get_parameter('ftf_hunter'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false'), 1))
|
||||
throw new InvalidParam('not_yet_found_only', "'$tmp'");
|
||||
if ($tmp == 'true')
|
||||
{
|
||||
$where_conds[] = "caches.founds = 0";
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# set_and
|
||||
#
|
||||
|
||||
if ($tmp = $request->get_parameter('set_and'))
|
||||
{
|
||||
# Check if the set exists.
|
||||
|
||||
$exists = Db::select_value("
|
||||
select 1
|
||||
from okapi_search_sets
|
||||
where id = '".mysql_real_escape_string($tmp)."'
|
||||
");
|
||||
if (!$exists)
|
||||
throw new InvalidParam('set_and', "Couldn't find a set by given ID.");
|
||||
$extra_tables[] = "okapi_search_results osr_and";
|
||||
$where_conds[] = "osr_and.cache_id = caches.cache_id";
|
||||
$where_conds[] = "osr_and.set_id = '".mysql_real_escape_string($tmp)."'";
|
||||
}
|
||||
|
||||
#
|
||||
# limit
|
||||
#
|
||||
@@ -464,6 +538,14 @@ class SearchAssistant
|
||||
}
|
||||
}
|
||||
|
||||
# To avoid join errors, put each of the $where_conds in extra paranthesis.
|
||||
|
||||
$tmp = array();
|
||||
foreach($where_conds as $cond)
|
||||
$tmp[] = "(".$cond.")";
|
||||
$where_conds = $tmp;
|
||||
unset($tmp);
|
||||
|
||||
$ret_array = array(
|
||||
'where_conds' => $where_conds,
|
||||
'offset' => (int)$offset,
|
||||
@@ -537,7 +619,10 @@ class SearchAssistant
|
||||
from cache_logs
|
||||
where
|
||||
user_id = '".mysql_real_escape_string($internal_user_id)."'
|
||||
and type = 1
|
||||
and type in (
|
||||
'".mysql_real_escape_string(Okapi::logtypename2id("Found it"))."',
|
||||
'".mysql_real_escape_string(Okapi::logtypename2id("Attended"))."'
|
||||
)
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
");
|
||||
}
|
||||
|
@@ -22,7 +22,10 @@ class WebService
|
||||
);
|
||||
}
|
||||
|
||||
private static $valid_field_names = array('uuid', 'cache_code', 'date', 'user', 'type', 'comment');
|
||||
private static $valid_field_names = array(
|
||||
'uuid', 'cache_code', 'date', 'user', 'type', 'was_recommended', 'comment',
|
||||
'internal_id',
|
||||
);
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
@@ -35,7 +38,7 @@ class WebService
|
||||
else
|
||||
$log_uuids = explode("|", $log_uuids);
|
||||
|
||||
if (count($log_uuids) > 500)
|
||||
if ((count($log_uuids) > 500) && (!$request->skip_limits))
|
||||
throw new InvalidParam('log_uuids', "Maximum allowed number of referenced ".
|
||||
"log entries is 500. You provided ".count($log_uuids)." UUIDs.");
|
||||
if (count($log_uuids) != count(array_unique($log_uuids)))
|
||||
@@ -48,9 +51,18 @@ class WebService
|
||||
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
||||
|
||||
$rs = Db::query("
|
||||
select cl.id, c.wp_oc as cache_code, cl.uuid, cl.type, unix_timestamp(cl.date) as date, cl.text,
|
||||
u.uuid as user_uuid, u.username, u.user_id
|
||||
from cache_logs cl, user u, caches c
|
||||
select
|
||||
cl.id, c.wp_oc as cache_code, cl.uuid, cl.type,
|
||||
unix_timestamp(cl.date) as date, cl.text,
|
||||
u.uuid as user_uuid, u.username, u.user_id,
|
||||
if(cr.user_id is null, 0, 1) as was_recommended
|
||||
from
|
||||
(cache_logs cl,
|
||||
user u,
|
||||
caches c)
|
||||
left join cache_rating cr
|
||||
on cr.user_id = u.user_id
|
||||
and cr.cache_id = c.cache_id
|
||||
where
|
||||
cl.uuid in ('".implode("','", array_map('mysql_real_escape_string', $log_uuids))."')
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
||||
@@ -71,7 +83,9 @@ class WebService
|
||||
'profile_url' => Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id'],
|
||||
),
|
||||
'type' => Okapi::logtypeid2name($row['type']),
|
||||
'comment' => $row['text']
|
||||
'was_recommended' => $row['was_recommended'] ? true : false,
|
||||
'comment' => $row['text'],
|
||||
'internal_id' => $row['id'],
|
||||
);
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
@@ -22,6 +22,6 @@
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given UUID haven't been found.
|
||||
(This behavior is different than in the services/logs/entry method, which
|
||||
responds with a HTTP 400 error in such case.)</p>
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -27,16 +27,33 @@
|
||||
</li>
|
||||
<li>
|
||||
<p><b>type</b> - string; log type. This could be <b>pretty much everything</b>, but
|
||||
there are three primary types: "Found it", "Didn't find it" or "Comment".
|
||||
You may treat every other string as "Comment".</p>
|
||||
there are five primary types:</p>
|
||||
<ul>
|
||||
<li>"Found it" and "Didn't find it" - for all Non-Event Caches,</li>
|
||||
<li>"Will attend" and "Attended" - for Event Caches,</li>
|
||||
<li>"Comment" - for all cache types.</li>
|
||||
</ul>
|
||||
<p>You may treat every other string as "Comment".</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>was_recommended</b> - true, if the author included his recommendation
|
||||
in this log entry,</p>
|
||||
</li>
|
||||
<li><b>comment</b> - HTML string, text entered with the log entry,</li>
|
||||
<li>
|
||||
<p><b>internal_id</b> - undocumented, you <u>should not</u> use
|
||||
this unless you really know you need to. Internal IDs are
|
||||
<b>not</b> unique across various OKAPI installations.
|
||||
Try to use UUIDs instead.</p>
|
||||
</li>
|
||||
<li><b>comment</b> - HTML string, text entered with the log entry.</li>
|
||||
</ul>
|
||||
<p>Note, that some fields can change in time (users can edit/delete
|
||||
their log entries).</p>
|
||||
</opt>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected.</p>
|
||||
<p>If given log entry does not exist, the method will
|
||||
respond with a HTTP 400 error.</p>
|
||||
respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -58,9 +58,11 @@ class WebService
|
||||
|
||||
# Getting the logs themselves. Formatting as an ordered list.
|
||||
|
||||
$logs = OkapiServiceRunner::call('services/logs/entries', new OkapiInternalRequest(
|
||||
$internal_request = new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('log_uuids' => implode("|", $log_uuids),
|
||||
'fields' => 'uuid|date|user|type|comment')));
|
||||
'fields' => $fields));
|
||||
$internal_request->skip_limits = true;
|
||||
$logs = OkapiServiceRunner::call('services/logs/entries', $internal_request);
|
||||
$results = array();
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
$results[] = $logs[$log_uuid];
|
||||
|
@@ -171,6 +171,7 @@ class WebService
|
||||
and type = '".mysql_real_escape_string(Okapi::logtypename2id($logtype))."'
|
||||
and date = from_unixtime('".mysql_real_escape_string($when)."')
|
||||
and text = '".mysql_real_escape_string($PSEUDOENCODED_comment)."'
|
||||
".((Settings::get('OC_BRANCH') == 'oc.pl') ? "and deleted = 0" : "")."
|
||||
limit 1
|
||||
");
|
||||
if ($duplicate_uuid != null)
|
||||
@@ -375,7 +376,7 @@ class WebService
|
||||
# We need to delete the copy of stats-picture for this user. Otherwise,
|
||||
# the legacy OC code won't detect that the picture needs to be refreshed.
|
||||
|
||||
$filepath = Settings::get('VAR_DIR').'images/statpics/statpic'.$user['internal_id'].'.jpg';
|
||||
$filepath = Okapi::get_var_dir().'/images/statpics/statpic'.$user['internal_id'].'.jpg';
|
||||
if (file_exists($filepath))
|
||||
unlink($filepath);
|
||||
|
||||
|
@@ -10,7 +10,8 @@
|
||||
</req>
|
||||
<req name='logtype'>
|
||||
<p>Type of an entry. This should be one of: <i>Found it</i>, <i>Didn't find it</i>
|
||||
or <i>Comment</i>.</p>
|
||||
or <i>Comment</i>. Currently this method does not support "Will attend" nor "Attended"
|
||||
log types which are used for Event Caches (we are planning to add this).</p>
|
||||
</req>
|
||||
<opt name='comment'>
|
||||
<p>Text to be submitted with the log entry. Plain-text (no HTML).</p>
|
||||
|
@@ -28,9 +28,9 @@
|
||||
</li>
|
||||
<li><b>cache_code</b> - code of the geocache,</li>
|
||||
<li>
|
||||
<p><b>type</b> - string; log type. This could be <b>pretty much everything</b>, but
|
||||
there are three primary types: "Found it", "Didn't find it" or "Comment".
|
||||
You may treat every other string as "Comment".</p>
|
||||
<p><b>type</b> - string; log type. This could be <b>pretty much
|
||||
everything</b>, but there are some primary types (see logs/entry
|
||||
method for more info).</p>
|
||||
</li>
|
||||
<li><b>comment</b> - HTML string, text entered with the log entry.</li>
|
||||
</ul>
|
||||
|
@@ -46,12 +46,12 @@
|
||||
OpenCaching installation.</p>
|
||||
</opt>
|
||||
<returns>
|
||||
<p>Technically, a 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>
|
||||
<p>Whether with callback_url or with a manual user entry - you will get
|
||||
your <b>oauth_verifier</b>, which allows you to continue the 3-legged
|
||||
authentication dance.</p>
|
||||
<p>If you used <b>callback_url</b>, you should wait for a 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>
|
||||
<ul>
|
||||
<li><b>oauth_token</b> - the Request Token that has been just authorized,</li>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
the user, then it has to be exchanged for an Access Token.</p>
|
||||
</desc>
|
||||
<req name='oauth_callback'>
|
||||
<p>An 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).
|
||||
If the client is unable to receive callbacks, the parameter
|
||||
must be set to "oob", OKAPI will provide a user with a
|
||||
|
@@ -7,7 +7,7 @@
|
||||
keep your database in sync with ours.</p>
|
||||
|
||||
<p>For some applications it might be desireable to have a quick access to the entire
|
||||
OpenCaching database (instead of quering 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
|
||||
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>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
only once in your lifetime.</p>
|
||||
|
||||
<p>For some applications it might be desireable to have a quick access to the entire
|
||||
OpenCaching database (instead of quering 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
|
||||
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>
|
||||
|
@@ -20,8 +20,7 @@ class ReplicateCommon
|
||||
{
|
||||
private static $chunk_size = 200;
|
||||
private static $logged_cache_fields = 'code|names|location|type|status|url|owner|founds|notfounds|size|size2|oxsize|difficulty|terrain|rating|rating_votes|recommendations|req_passwd|descriptions|hints|images|trackables_count|trackables|alt_wpts|last_found|last_modified|date_created|date_hidden';
|
||||
|
||||
private static $logged_log_entry_fields = 'uuid|cache_code|date|user|type|comment';
|
||||
private static $logged_log_entry_fields = 'uuid|cache_code|date|user|type|was_recommended|comment';
|
||||
|
||||
/** Return current (greatest) changelog revision number. */
|
||||
public static function get_revision()
|
||||
|
@@ -17,6 +17,6 @@
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected.</p>
|
||||
<p>If given user does not exist, the method will respond with a HTTP 400 error.</p>
|
||||
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -19,6 +19,6 @@
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given user haven't been found.
|
||||
(This behavior is different than in the services/users/by_username method, which
|
||||
responds with a HTTP 400 error in such case.)</p>
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -38,6 +38,6 @@
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
<p>A dictionary of fields you have selected.</p>
|
||||
<p>If given user does not exist, the method will respond with a HTTP 400 error.</p>
|
||||
<p>If given user does not exist, the method will respond with an HTTP 400 error.</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -19,6 +19,6 @@
|
||||
and each value will be a dictionary of fields you have selected.</p>
|
||||
<p>Value of <b>null</b> means that the given user haven't been found.
|
||||
(This behavior is different than in the services/users/user method, which
|
||||
responds with a HTTP 400 error in such case.)</p>
|
||||
responds with an HTTP 400 error in such case.)</p>
|
||||
</returns>
|
||||
</xml>
|
@@ -143,8 +143,14 @@ final class Settings
|
||||
private static function load_settings()
|
||||
{
|
||||
try {
|
||||
# This is an external code and it MAY generate E_NOTICEs.
|
||||
# We have to temporarilly disable our default error handler.
|
||||
|
||||
OkapiErrorHandler::disable();
|
||||
require_once($GLOBALS['rootpath']."okapi_settings.php");
|
||||
$ref = get_okapi_settings();
|
||||
OkapiErrorHandler::reenable();
|
||||
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("Could not import <rootpath>/okapi_settings.php:\n".$e->getMessage());
|
||||
}
|
||||
|
@@ -1,185 +0,0 @@
|
||||
.dp-highlighter
|
||||
{
|
||||
font-family: "Consolas", "Courier New", Courier, mono, serif;
|
||||
font-size: 12px;
|
||||
background-color: #E7E5DC;
|
||||
width: 99%;
|
||||
overflow: auto;
|
||||
margin: 18px 0 18px 0 !important;
|
||||
padding-top: 1px; /* adds a little border on top when controls are hidden */
|
||||
}
|
||||
|
||||
/* clear styles */
|
||||
.dp-highlighter ol,
|
||||
.dp-highlighter ol li,
|
||||
.dp-highlighter ol li span
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.dp-highlighter a,
|
||||
.dp-highlighter a:hover
|
||||
{
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dp-highlighter .bar
|
||||
{
|
||||
padding-left: 45px;
|
||||
}
|
||||
|
||||
.dp-highlighter.collapsed .bar,
|
||||
.dp-highlighter.nogutter .bar
|
||||
{
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.dp-highlighter ol
|
||||
{
|
||||
list-style: decimal; /* for ie */
|
||||
background-color: #fff;
|
||||
margin: 0px 0px 1px 45px !important; /* 1px bottom margin seems to fix occasional Firefox scrolling */
|
||||
padding: 0px;
|
||||
color: #5C5C5C;
|
||||
}
|
||||
|
||||
.dp-highlighter.nogutter ol,
|
||||
.dp-highlighter.nogutter ol li
|
||||
{
|
||||
list-style: none !important;
|
||||
margin-left: 0px !important;
|
||||
}
|
||||
|
||||
.dp-highlighter ol li,
|
||||
.dp-highlighter .columns div
|
||||
{
|
||||
list-style: decimal-leading-zero; /* better look for others, override cascade from OL */
|
||||
list-style-position: outside !important;
|
||||
border-left: 3px solid #6CE26C;
|
||||
background-color: #F8F8F8;
|
||||
color: #5C5C5C;
|
||||
padding: 0 3px 0 10px !important;
|
||||
margin: 0 !important;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.dp-highlighter.nogutter ol li,
|
||||
.dp-highlighter.nogutter .columns div
|
||||
{
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dp-highlighter .columns
|
||||
{
|
||||
background-color: #F8F8F8;
|
||||
color: gray;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dp-highlighter .columns div
|
||||
{
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.dp-highlighter ol li.alt
|
||||
{
|
||||
/*background-color: #FFF;*/
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.dp-highlighter ol li span
|
||||
{
|
||||
color: black;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
/* Adjust some properties when collapsed */
|
||||
|
||||
.dp-highlighter.collapsed ol
|
||||
{
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.dp-highlighter.collapsed ol li
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Additional modifications when in print-view */
|
||||
|
||||
.dp-highlighter.printing
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
|
||||
.dp-highlighter.printing .tools
|
||||
{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.dp-highlighter.printing li
|
||||
{
|
||||
display: list-item !important;
|
||||
}
|
||||
|
||||
/* Styles for the tools */
|
||||
|
||||
.dp-highlighter .tools
|
||||
{
|
||||
padding: 3px 8px 3px 10px;
|
||||
font: 9px Verdana, Geneva, Arial, Helvetica, sans-serif;
|
||||
color: silver;
|
||||
background-color: #f8f8f8;
|
||||
padding-bottom: 10px;
|
||||
border-left: 3px solid #6CE26C;
|
||||
}
|
||||
|
||||
.dp-highlighter.nogutter .tools
|
||||
{
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.dp-highlighter.collapsed .tools
|
||||
{
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.dp-highlighter .tools a
|
||||
{
|
||||
font-size: 9px;
|
||||
color: #a0a0a0;
|
||||
background-color: inherit;
|
||||
text-decoration: none;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.dp-highlighter .tools a:hover
|
||||
{
|
||||
color: red;
|
||||
background-color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* About dialog styles */
|
||||
|
||||
.dp-about { background-color: #fff; color: #333; margin: 0px; padding: 0px; }
|
||||
.dp-about table { width: 100%; height: 100%; font-size: 11px; font-family: Tahoma, Verdana, Arial, sans-serif !important; }
|
||||
.dp-about td { padding: 10px; vertical-align: top; }
|
||||
.dp-about .copy { border-bottom: 1px solid #ACA899; height: 95%; }
|
||||
.dp-about .title { color: red; background-color: inherit; font-weight: bold; }
|
||||
.dp-about .para { margin: 0 0 4px 0; }
|
||||
.dp-about .footer { background-color: #ECEADB; color: #333; border-top: 1px solid #fff; text-align: right; }
|
||||
.dp-about .close { font-size: 11px; font-family: Tahoma, Verdana, Arial, sans-serif !important; background-color: #ECEADB; color: #333; width: 60px; height: 22px; }
|
||||
|
||||
/* Language specific styles */
|
||||
|
||||
.dp-highlighter .comment, .dp-highlighter .comments { color: #008200; background-color: inherit; }
|
||||
.dp-highlighter .string { color: blue; background-color: inherit; }
|
||||
.dp-highlighter .keyword { color: #069; font-weight: bold; background-color: inherit; }
|
||||
.dp-highlighter .preprocessor { color: gray; background-color: inherit; }
|
Binary file not shown.
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.CSharp=function()
|
||||
{var keywords='abstract as base bool break byte case catch char checked class const '+'continue decimal default delegate do double else enum event explicit '+'extern false finally fixed float for foreach get goto if implicit in int '+'interface internal is lock long namespace new null object operator out '+'override params private protected public readonly ref return sbyte sealed set '+'short sizeof stackalloc static string struct switch this throw true try '+'typeof uint ulong unchecked unsafe ushort using virtual void while';this.regexList=[{regex:dp.sh.RegexLib.SingleLineCComments,css:'comment'},{regex:dp.sh.RegexLib.MultiLineCComments,css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp('^\\s*#.*','gm'),css:'preprocessor'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'}];this.CssClass='dp-c';this.Style='.dp-c .vars { color: #d00; }';}
|
||||
dp.sh.Brushes.CSharp.prototype=new dp.sh.Highlighter();dp.sh.Brushes.CSharp.Aliases=['c#','c-sharp','csharp'];
|
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Cpp=function()
|
||||
{var datatypes='ATOM BOOL BOOLEAN BYTE CHAR COLORREF DWORD DWORDLONG DWORD_PTR '+'DWORD32 DWORD64 FLOAT HACCEL HALF_PTR HANDLE HBITMAP HBRUSH '+'HCOLORSPACE HCONV HCONVLIST HCURSOR HDC HDDEDATA HDESK HDROP HDWP '+'HENHMETAFILE HFILE HFONT HGDIOBJ HGLOBAL HHOOK HICON HINSTANCE HKEY '+'HKL HLOCAL HMENU HMETAFILE HMODULE HMONITOR HPALETTE HPEN HRESULT '+'HRGN HRSRC HSZ HWINSTA HWND INT INT_PTR INT32 INT64 LANGID LCID LCTYPE '+'LGRPID LONG LONGLONG LONG_PTR LONG32 LONG64 LPARAM LPBOOL LPBYTE LPCOLORREF '+'LPCSTR LPCTSTR LPCVOID LPCWSTR LPDWORD LPHANDLE LPINT LPLONG LPSTR LPTSTR '+'LPVOID LPWORD LPWSTR LRESULT PBOOL PBOOLEAN PBYTE PCHAR PCSTR PCTSTR PCWSTR '+'PDWORDLONG PDWORD_PTR PDWORD32 PDWORD64 PFLOAT PHALF_PTR PHANDLE PHKEY PINT '+'PINT_PTR PINT32 PINT64 PLCID PLONG PLONGLONG PLONG_PTR PLONG32 PLONG64 POINTER_32 '+'POINTER_64 PSHORT PSIZE_T PSSIZE_T PSTR PTBYTE PTCHAR PTSTR PUCHAR PUHALF_PTR '+'PUINT PUINT_PTR PUINT32 PUINT64 PULONG PULONGLONG PULONG_PTR PULONG32 PULONG64 '+'PUSHORT PVOID PWCHAR PWORD PWSTR SC_HANDLE SC_LOCK SERVICE_STATUS_HANDLE SHORT '+'SIZE_T SSIZE_T TBYTE TCHAR UCHAR UHALF_PTR UINT UINT_PTR UINT32 UINT64 ULONG '+'ULONGLONG ULONG_PTR ULONG32 ULONG64 USHORT USN VOID WCHAR WORD WPARAM WPARAM WPARAM '+'char bool short int __int32 __int64 __int8 __int16 long float double __wchar_t '+'clock_t _complex _dev_t _diskfree_t div_t ldiv_t _exception _EXCEPTION_POINTERS '+'FILE _finddata_t _finddatai64_t _wfinddata_t _wfinddatai64_t __finddata64_t '+'__wfinddata64_t _FPIEEE_RECORD fpos_t _HEAPINFO _HFILE lconv intptr_t '+'jmp_buf mbstate_t _off_t _onexit_t _PNH ptrdiff_t _purecall_handler '+'sig_atomic_t size_t _stat __stat64 _stati64 terminate_function '+'time_t __time64_t _timeb __timeb64 tm uintptr_t _utimbuf '+'va_list wchar_t wctrans_t wctype_t wint_t signed';var keywords='break case catch class const __finally __exception __try '+'const_cast continue private public protected __declspec '+'default delete deprecated dllexport dllimport do dynamic_cast '+'else enum explicit extern if for friend goto inline '+'mutable naked namespace new noinline noreturn nothrow '+'register reinterpret_cast return selectany '+'sizeof static static_cast struct switch template this '+'thread throw true false try typedef typeid typename union '+'using uuid virtual void volatile whcar_t while';this.regexList=[{regex:dp.sh.RegexLib.SingleLineCComments,css:'comment'},{regex:dp.sh.RegexLib.MultiLineCComments,css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp('^ *#.*','gm'),css:'preprocessor'},{regex:new RegExp(this.GetKeywords(datatypes),'gm'),css:'datatypes'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'}];this.CssClass='dp-cpp';this.Style='.dp-cpp .datatypes { color: #2E8B57; font-weight: bold; }';}
|
||||
dp.sh.Brushes.Cpp.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Cpp.Aliases=['cpp','c','c++'];
|
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.CSS=function()
|
||||
{var keywords='ascent azimuth background-attachment background-color background-image background-position '+'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top '+'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color '+'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width '+'border-bottom-width border-left-width border-width border cap-height caption-side centerline clear clip color '+'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display '+'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font '+'height letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top '+'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans '+'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page '+'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position '+'quotes richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress '+'table-layout text-align text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em '+'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index';var values='above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero default digits disc dotted double '+'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';var fonts='[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif';this.regexList=[{regex:dp.sh.RegexLib.MultiLineCComments,css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp('\\#[a-zA-Z0-9]{3,6}','g'),css:'value'},{regex:new RegExp('(-?\\d+)(\.\\d+)?(px|em|pt|\:|\%|)','g'),css:'value'},{regex:new RegExp('!important','g'),css:'important'},{regex:new RegExp(this.GetKeywordsCSS(keywords),'gm'),css:'keyword'},{regex:new RegExp(this.GetValuesCSS(values),'g'),css:'value'},{regex:new RegExp(this.GetValuesCSS(fonts),'g'),css:'value'}];this.CssClass='dp-css';this.Style='.dp-css .value { color: black; }'+'.dp-css .important { color: red; }';}
|
||||
dp.sh.Highlighter.prototype.GetKeywordsCSS=function(str)
|
||||
{return'\\b([a-z_]|)'+str.replace(/ /g,'(?=:)\\b|\\b([a-z_\\*]|\\*|)')+'(?=:)\\b';}
|
||||
dp.sh.Highlighter.prototype.GetValuesCSS=function(str)
|
||||
{return'\\b'+str.replace(/ /g,'(?!-)(?!:)\\b|\\b()')+'\:\\b';}
|
||||
dp.sh.Brushes.CSS.prototype=new dp.sh.Highlighter();dp.sh.Brushes.CSS.Aliases=['css'];
|
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Delphi=function()
|
||||
{var keywords='abs addr and ansichar ansistring array as asm begin boolean byte cardinal '+'case char class comp const constructor currency destructor div do double '+'downto else end except exports extended false file finalization finally '+'for function goto if implementation in inherited int64 initialization '+'integer interface is label library longint longword mod nil not object '+'of on or packed pansichar pansistring pchar pcurrency pdatetime pextended '+'pint64 pointer private procedure program property pshortstring pstring '+'pvariant pwidechar pwidestring protected public published raise real real48 '+'record repeat set shl shortint shortstring shr single smallint string then '+'threadvar to true try type unit until uses val var varirnt while widechar '+'widestring with word write writeln xor';this.regexList=[{regex:new RegExp('\\(\\*[\\s\\S]*?\\*\\)','gm'),css:'comment'},{regex:new RegExp('{(?!\\$)[\\s\\S]*?}','gm'),css:'comment'},{regex:dp.sh.RegexLib.SingleLineCComments,css:'comment'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp('\\{\\$[a-zA-Z]+ .+\\}','g'),css:'directive'},{regex:new RegExp('\\b[\\d\\.]+\\b','g'),css:'number'},{regex:new RegExp('\\$[a-zA-Z0-9]+\\b','g'),css:'number'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'}];this.CssClass='dp-delphi';this.Style='.dp-delphi .number { color: blue; }'+'.dp-delphi .directive { color: #008284; }'+'.dp-delphi .vars { color: #000; }';}
|
||||
dp.sh.Brushes.Delphi.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Delphi.Aliases=['delphi','pascal'];
|
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.JScript=function()
|
||||
{var keywords='abstract boolean break byte case catch char class const continue debugger '+'default delete do double else enum export extends false final finally float '+'for function goto if implements import in instanceof int interface long native '+'new null package private protected public return short static super switch '+'synchronized this throw throws transient true try typeof var void volatile while with';this.regexList=[{regex:dp.sh.RegexLib.SingleLineCComments,css:'comment'},{regex:dp.sh.RegexLib.MultiLineCComments,css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp('^\\s*#.*','gm'),css:'preprocessor'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'}];this.CssClass='dp-c';}
|
||||
dp.sh.Brushes.JScript.prototype=new dp.sh.Highlighter();dp.sh.Brushes.JScript.Aliases=['js','jscript','javascript'];
|
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Java=function()
|
||||
{var keywords='abstract assert boolean break byte case catch char class const '+'continue default do double else enum extends '+'false final finally float for goto if implements import '+'instanceof int interface long native new null '+'package private protected public return '+'short static strictfp super switch synchronized this throw throws true '+'transient try void volatile while';this.regexList=[{regex:dp.sh.RegexLib.SingleLineCComments,css:'comment'},{regex:dp.sh.RegexLib.MultiLineCComments,css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp('\\b([\\d]+(\\.[\\d]+)?|0x[a-f0-9]+)\\b','gi'),css:'number'},{regex:new RegExp('(?!\\@interface\\b)\\@[\\$\\w]+\\b','g'),css:'annotation'},{regex:new RegExp('\\@interface\\b','g'),css:'keyword'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'}];this.CssClass='dp-j';this.Style='.dp-j .annotation { color: #646464; }'+'.dp-j .number { color: #C00000; }';}
|
||||
dp.sh.Brushes.Java.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Java.Aliases=['java'];
|
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Php=function()
|
||||
{var funcs='abs acos acosh addcslashes addslashes '+'array_change_key_case array_chunk array_combine array_count_values array_diff '+'array_diff_assoc array_diff_key array_diff_uassoc array_diff_ukey array_fill '+'array_filter array_flip array_intersect array_intersect_assoc array_intersect_key '+'array_intersect_uassoc array_intersect_ukey array_key_exists array_keys array_map '+'array_merge array_merge_recursive array_multisort array_pad array_pop array_product '+'array_push array_rand array_reduce array_reverse array_search array_shift '+'array_slice array_splice array_sum array_udiff array_udiff_assoc '+'array_udiff_uassoc array_uintersect array_uintersect_assoc '+'array_uintersect_uassoc array_unique array_unshift array_values array_walk '+'array_walk_recursive atan atan2 atanh base64_decode base64_encode base_convert '+'basename bcadd bccomp bcdiv bcmod bcmul bindec bindtextdomain bzclose bzcompress '+'bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite ceil chdir '+'checkdate checkdnsrr chgrp chmod chop chown chr chroot chunk_split class_exists '+'closedir closelog copy cos cosh count count_chars date decbin dechex decoct '+'deg2rad delete ebcdic2ascii echo empty end ereg ereg_replace eregi eregi_replace error_log '+'error_reporting escapeshellarg escapeshellcmd eval exec exit exp explode extension_loaded '+'feof fflush fgetc fgetcsv fgets fgetss file_exists file_get_contents file_put_contents '+'fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype '+'floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv fputs fread fscanf '+'fseek fsockopen fstat ftell ftok getallheaders getcwd getdate getenv gethostbyaddr gethostbyname '+'gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid getmyuid getopt '+'getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext '+'gettimeofday gettype glob gmdate gmmktime ini_alter ini_get ini_get_all ini_restore ini_set '+'interface_exists intval ip2long is_a is_array is_bool is_callable is_dir is_double '+'is_executable is_file is_finite is_float is_infinite is_int is_integer is_link is_long '+'is_nan is_null is_numeric is_object is_readable is_real is_resource is_scalar is_soap_fault '+'is_string is_subclass_of is_uploaded_file is_writable is_writeable mkdir mktime nl2br '+'parse_ini_file parse_str parse_url passthru pathinfo readlink realpath rewind rewinddir rmdir '+'round str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split '+'str_word_count strcasecmp strchr strcmp strcoll strcspn strftime strip_tags stripcslashes '+'stripos stripslashes stristr strlen strnatcasecmp strnatcmp strncasecmp strncmp strpbrk '+'strpos strptime strrchr strrev strripos strrpos strspn strstr strtok strtolower strtotime '+'strtoupper strtr strval substr substr_compare';var keywords='and or xor __FILE__ __LINE__ array as break case '+'cfunction class const continue declare default die do else '+'elseif empty enddeclare endfor endforeach endif endswitch endwhile '+'extends for foreach function include include_once global if '+'new old_function return static switch use require require_once '+'var while __FUNCTION__ __CLASS__ '+'__METHOD__ abstract interface public implements extends private protected throw';this.regexList=[{regex:dp.sh.RegexLib.SingleLineCComments,css:'comment'},{regex:dp.sh.RegexLib.MultiLineCComments,css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp('\\$\\w+','g'),css:'vars'},{regex:new RegExp(this.GetKeywords(funcs),'gmi'),css:'func'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'}];this.CssClass='dp-c';}
|
||||
dp.sh.Brushes.Php.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Php.Aliases=['php'];
|
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Python=function()
|
||||
{var keywords='and assert break class continue def del elif else '+'except exec finally for from global if import in is '+'lambda not or pass print raise return try yield while';var special='None True False self cls class_'
|
||||
this.regexList=[{regex:dp.sh.RegexLib.SingleLinePerlComments,css:'comment'},{regex:new RegExp("^\\s*@\\w+",'gm'),css:'decorator'},{regex:new RegExp("(['\"]{3})([^\\1])*?\\1",'gm'),css:'comment'},{regex:new RegExp('"(?!")(?:\\.|\\\\\\"|[^\\""\\n\\r])*"','gm'),css:'string'},{regex:new RegExp("'(?!')*(?:\\.|(\\\\\\')|[^\\''\\n\\r])*'",'gm'),css:'string'},{regex:new RegExp("\\b\\d+\\.?\\w*",'g'),css:'number'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'},{regex:new RegExp(this.GetKeywords(special),'gm'),css:'special'}];this.CssClass='dp-py';this.Style='.dp-py .builtins { color: #ff1493; }'+'.dp-py .magicmethods { color: #808080; }'+'.dp-py .exceptions { color: brown; }'+'.dp-py .types { color: brown; font-style: italic; }'+'.dp-py .commonlibs { color: #8A2BE2; font-style: italic; }';}
|
||||
dp.sh.Brushes.Python.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Python.Aliases=['py','python'];
|
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Ruby=function()
|
||||
{var keywords='alias and BEGIN begin break case class def define_method defined do each else elsif '+'END end ensure false for if in module new next nil not or raise redo rescue retry return '+'self super then throw true undef unless until when while yield';var builtins='Array Bignum Binding Class Continuation Dir Exception FalseClass File::Stat File Fixnum Fload '+'Hash Integer IO MatchData Method Module NilClass Numeric Object Proc Range Regexp String Struct::TMS Symbol '+'ThreadGroup Thread Time TrueClass'
|
||||
this.regexList=[{regex:dp.sh.RegexLib.SingleLinePerlComments,css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp(':[a-z][A-Za-z0-9_]*','g'),css:'symbol'},{regex:new RegExp('(\\$|@@|@)\\w+','g'),css:'variable'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'},{regex:new RegExp(this.GetKeywords(builtins),'gm'),css:'builtin'}];this.CssClass='dp-rb';this.Style='.dp-rb .symbol { color: #a70; }'+'.dp-rb .variable { color: #a70; font-weight: bold; }';}
|
||||
dp.sh.Brushes.Ruby.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Ruby.Aliases=['ruby','rails','ror'];
|
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Sql=function()
|
||||
{var funcs='abs avg case cast coalesce convert count current_timestamp '+'current_user day isnull left lower month nullif replace right '+'session_user space substring sum system_user upper user year';var keywords='absolute action add after alter as asc at authorization begin bigint '+'binary bit by cascade char character check checkpoint close collate '+'column commit committed connect connection constraint contains continue '+'create cube current current_date current_time cursor database date '+'deallocate dec decimal declare default delete desc distinct double drop '+'dynamic else end end-exec escape except exec execute false fetch first '+'float for force foreign forward free from full function global goto grant '+'group grouping having hour ignore index inner insensitive insert instead '+'int integer intersect into is isolation key last level load local max min '+'minute modify move name national nchar next no numeric of off on only '+'open option order out output partial password precision prepare primary '+'prior privileges procedure public read real references relative repeatable '+'restrict return returns revoke rollback rollup rows rule schema scroll '+'second section select sequence serializable set size smallint static '+'statistics table temp temporary then time timestamp to top transaction '+'translation trigger true truncate uncommitted union unique update values '+'varchar varying view when where with work';var operators='all and any between cross in join like not null or outer some';this.regexList=[{regex:new RegExp('--(.*)$','gm'),css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:dp.sh.RegexLib.SingleQuotedString,css:'string'},{regex:new RegExp(this.GetKeywords(funcs),'gmi'),css:'func'},{regex:new RegExp(this.GetKeywords(operators),'gmi'),css:'op'},{regex:new RegExp(this.GetKeywords(keywords),'gmi'),css:'keyword'}];this.CssClass='dp-sql';this.Style='.dp-sql .func { color: #ff1493; }'+'.dp-sql .op { color: #808080; }';}
|
||||
dp.sh.Brushes.Sql.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Sql.Aliases=['sql'];
|
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Vb=function()
|
||||
{var keywords='AddHandler AddressOf AndAlso Alias And Ansi As Assembly Auto '+'Boolean ByRef Byte ByVal Call Case Catch CBool CByte CChar CDate '+'CDec CDbl Char CInt Class CLng CObj Const CShort CSng CStr CType '+'Date Decimal Declare Default Delegate Dim DirectCast Do Double Each '+'Else ElseIf End Enum Erase Error Event Exit False Finally For Friend '+'Function Get GetType GoSub GoTo Handles If Implements Imports In '+'Inherits Integer Interface Is Let Lib Like Long Loop Me Mod Module '+'MustInherit MustOverride MyBase MyClass Namespace New Next Not Nothing '+'NotInheritable NotOverridable Object On Option Optional Or OrElse '+'Overloads Overridable Overrides ParamArray Preserve Private Property '+'Protected Public RaiseEvent ReadOnly ReDim REM RemoveHandler Resume '+'Return Select Set Shadows Shared Short Single Static Step Stop String '+'Structure Sub SyncLock Then Throw To True Try TypeOf Unicode Until '+'Variant When While With WithEvents WriteOnly Xor';this.regexList=[{regex:new RegExp('\'.*$','gm'),css:'comment'},{regex:dp.sh.RegexLib.DoubleQuotedString,css:'string'},{regex:new RegExp('^\\s*#.*','gm'),css:'preprocessor'},{regex:new RegExp(this.GetKeywords(keywords),'gm'),css:'keyword'}];this.CssClass='dp-vb';}
|
||||
dp.sh.Brushes.Vb.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Vb.Aliases=['vb','vb.net'];
|
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
dp.sh.Brushes.Xml=function()
|
||||
{this.CssClass='dp-xml';this.Style='.dp-xml .cdata { color: #ff1493; }'+'.dp-xml .tag, .dp-xml .tag-name { color: #069; font-weight: bold; }'+'.dp-xml .attribute { color: red; }'+'.dp-xml .attribute-value { color: blue; }';}
|
||||
dp.sh.Brushes.Xml.prototype=new dp.sh.Highlighter();dp.sh.Brushes.Xml.Aliases=['xml','xhtml','xslt','html','xhtml'];dp.sh.Brushes.Xml.prototype.ProcessRegexList=function()
|
||||
{function push(array,value)
|
||||
{array[array.length]=value;}
|
||||
var index=0;var match=null;var regex=null;this.GetMatches(new RegExp('(\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\>|>)','gm'),'cdata');this.GetMatches(new RegExp('(\<|<)!--\\s*.*?\\s*--(\>|>)','gm'),'comments');regex=new RegExp('([:\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\'|\\w+)*|(\\w+)','gm');while((match=regex.exec(this.code))!=null)
|
||||
{if(match[1]==null)
|
||||
{continue;}
|
||||
push(this.matches,new dp.sh.Match(match[1],match.index,'attribute'));if(match[2]!=undefined)
|
||||
{push(this.matches,new dp.sh.Match(match[2],match.index+match[0].indexOf(match[2]),'attribute-value'));}}
|
||||
this.GetMatches(new RegExp('(\<|<)/*\\?*(?!\\!)|/*\\?*(\>|>)','gm'),'tag');regex=new RegExp('(?:\<|<)/*\\?*\\s*([:\\w-\.]+)','gm');while((match=regex.exec(this.code))!=null)
|
||||
{push(this.matches,new dp.sh.Match(match[1],match.index+match[0].indexOf(match[1]),'tag-name'));}}
|
161
htdocs/okapi/static/syntax_highlighter/shCore.js
vendored
161
htdocs/okapi/static/syntax_highlighter/shCore.js
vendored
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* JsMin
|
||||
* Javascript Compressor
|
||||
* http://www.crockford.com/
|
||||
* http://www.smallsharptools.com/
|
||||
*/
|
||||
|
||||
var dp={sh:{Toolbar:{},Utils:{},RegexLib:{},Brushes:{},Strings:{AboutDialog:'<html><head><title>About...</title></head><body class="dp-about"><table cellspacing="0"><tr><td class="copy"><p class="title">dp.SyntaxHighlighter</div><div class="para">Version: {V}</p><p><a href="http://www.dreamprojections.com/syntaxhighlighter/?ref=about" target="_blank">http://www.dreamprojections.com/syntaxhighlighter</a></p>©2004-2007 Alex Gorbatchev.</td></tr><tr><td class="footer"><input type="button" class="close" value="OK" onClick="window.close()"/></td></tr></table></body></html>'},ClipboardSwf:null,Version:'1.5.1'}};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:'+ expand source',check:function(highlighter){return highlighter.collapse;},func:function(sender,highlighter)
|
||||
{sender.parentNode.removeChild(sender);highlighter.div.className=highlighter.div.className.replace('collapsed','');}},ViewSource:{label:'view plain',func:function(sender,highlighter)
|
||||
{var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/</g,'<');var wnd=window.open('','_blank','width=750, height=400, location=0, resizable=1, menubar=0, scrollbars=0');wnd.document.write('<textarea style="width:99%;height:99%">'+code+'</textarea>');wnd.document.close();}},CopyToClipboard:{label:'copy to clipboard',check:function(){return window.clipboardData!=null||dp.sh.ClipboardSwf!=null;},func:function(sender,highlighter)
|
||||
{var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');if(window.clipboardData)
|
||||
{window.clipboardData.setData('text',code);}
|
||||
else if(dp.sh.ClipboardSwf!=null)
|
||||
{var flashcopier=highlighter.flashCopier;if(flashcopier==null)
|
||||
{flashcopier=document.createElement('div');highlighter.flashCopier=flashcopier;highlighter.div.appendChild(flashcopier);}
|
||||
flashcopier.innerHTML='<embed src="'+dp.sh.ClipboardSwf+'" FlashVars="clipboard='+encodeURIComponent(code)+'" width="0" height="0" type="application/x-shockwave-flash"></embed>';}
|
||||
alert('The code is in your clipboard now');}},PrintSource:{label:'print',func:function(sender,highlighter)
|
||||
{var iframe=document.createElement('IFRAME');var doc=null;iframe.style.cssText='position:absolute;width:0px;height:0px;left:-500px;top:-500px;';document.body.appendChild(iframe);doc=iframe.contentWindow.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write('<div class="'+highlighter.div.className.replace('collapsed','')+' printing">'+highlighter.div.innerHTML+'</div>');doc.close();iframe.contentWindow.focus();iframe.contentWindow.print();alert('Printing...');document.body.removeChild(iframe);}},About:{label:'?',func:function(highlighter)
|
||||
{var wnd=window.open('','_blank','dialog,width=300,height=150,scrollbars=0');var doc=wnd.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace('{V}',dp.sh.Version));doc.close();wnd.focus();}}};dp.sh.Toolbar.Create=function(highlighter)
|
||||
{var div=document.createElement('DIV');div.className='tools';for(var name in dp.sh.Toolbar.Commands)
|
||||
{var cmd=dp.sh.Toolbar.Commands[name];if(cmd.check!=null&&!cmd.check(highlighter))
|
||||
continue;div.innerHTML+='<a href="#" onclick="dp.sh.Toolbar.Command(\''+name+'\',this);return false;">'+cmd.label+'</a>';}
|
||||
return div;}
|
||||
dp.sh.Toolbar.Command=function(name,sender)
|
||||
{var n=sender;while(n!=null&&n.className.indexOf('dp-highlighter')==-1)
|
||||
n=n.parentNode;if(n!=null)
|
||||
dp.sh.Toolbar.Commands[name].func(sender,n.highlighter);}
|
||||
dp.sh.Utils.CopyStyles=function(destDoc,sourceDoc)
|
||||
{var links=sourceDoc.getElementsByTagName('link');for(var i=0;i<links.length;i++)
|
||||
if(links[i].rel.toLowerCase()=='stylesheet')
|
||||
destDoc.write('<link type="text/css" rel="stylesheet" href="'+links[i].href+'"></link>');}
|
||||
dp.sh.Utils.FixForBlogger=function(str)
|
||||
{return(dp.sh.isBloggerMode==true)?str.replace(/<br\s*\/?>|<br\s*\/?>/gi,'\n'):str;}
|
||||
dp.sh.RegexLib={MultiLineCComments:new RegExp('/\\*[\\s\\S]*?\\*/','gm'),SingleLineCComments:new RegExp('//.*$','gm'),SingleLinePerlComments:new RegExp('#.*$','gm'),DoubleQuotedString:new RegExp('"(?:\\.|(\\\\\\")|[^\\""\\n])*"','g'),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''\\n])*'",'g')};dp.sh.Match=function(value,index,css)
|
||||
{this.value=value;this.index=index;this.length=value.length;this.css=css;}
|
||||
dp.sh.Highlighter=function()
|
||||
{this.noGutter=false;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;}
|
||||
dp.sh.Highlighter.SortCallback=function(m1,m2)
|
||||
{if(m1.index<m2.index)
|
||||
return-1;else if(m1.index>m2.index)
|
||||
return 1;else
|
||||
{if(m1.length<m2.length)
|
||||
return-1;else if(m1.length>m2.length)
|
||||
return 1;}
|
||||
return 0;}
|
||||
dp.sh.Highlighter.prototype.CreateElement=function(name)
|
||||
{var result=document.createElement(name);result.highlighter=this;return result;}
|
||||
dp.sh.Highlighter.prototype.GetMatches=function(regex,css)
|
||||
{var index=0;var match=null;while((match=regex.exec(this.code))!=null)
|
||||
this.matches[this.matches.length]=new dp.sh.Match(match[0],match.index,css);}
|
||||
dp.sh.Highlighter.prototype.AddBit=function(str,css)
|
||||
{if(str==null||str.length==0)
|
||||
return;var span=this.CreateElement('SPAN');str=str.replace(/ /g,' ');str=str.replace(/</g,'<');str=str.replace(/\n/gm,' <br>');if(css!=null)
|
||||
{if((/br/gi).test(str))
|
||||
{var lines=str.split(' <br>');for(var i=0;i<lines.length;i++)
|
||||
{span=this.CreateElement('SPAN');span.className=css;span.innerHTML=lines[i];this.div.appendChild(span);if(i+1<lines.length)
|
||||
this.div.appendChild(this.CreateElement('BR'));}}
|
||||
else
|
||||
{span.className=css;span.innerHTML=str;this.div.appendChild(span);}}
|
||||
else
|
||||
{span.innerHTML=str;this.div.appendChild(span);}}
|
||||
dp.sh.Highlighter.prototype.IsInside=function(match)
|
||||
{if(match==null||match.length==0)
|
||||
return false;for(var i=0;i<this.matches.length;i++)
|
||||
{var c=this.matches[i];if(c==null)
|
||||
continue;if((match.index>c.index)&&(match.index<c.index+c.length))
|
||||
return true;}
|
||||
return false;}
|
||||
dp.sh.Highlighter.prototype.ProcessRegexList=function()
|
||||
{for(var i=0;i<this.regexList.length;i++)
|
||||
this.GetMatches(this.regexList[i].regex,this.regexList[i].css);}
|
||||
dp.sh.Highlighter.prototype.ProcessSmartTabs=function(code)
|
||||
{var lines=code.split('\n');var result='';var tabSize=4;var tab='\t';function InsertSpaces(line,pos,count)
|
||||
{var left=line.substr(0,pos);var right=line.substr(pos+1,line.length);var spaces='';for(var i=0;i<count;i++)
|
||||
spaces+=' ';return left+spaces+right;}
|
||||
function ProcessLine(line,tabSize)
|
||||
{if(line.indexOf(tab)==-1)
|
||||
return line;var pos=0;while((pos=line.indexOf(tab))!=-1)
|
||||
{var spaces=tabSize-pos%tabSize;line=InsertSpaces(line,pos,spaces);}
|
||||
return line;}
|
||||
for(var i=0;i<lines.length;i++)
|
||||
result+=ProcessLine(lines[i],tabSize)+'\n';return result;}
|
||||
dp.sh.Highlighter.prototype.SwitchToList=function()
|
||||
{var html=this.div.innerHTML.replace(/<(br)\/?>/gi,'\n');var lines=html.split('\n');if(this.addControls==true)
|
||||
this.bar.appendChild(dp.sh.Toolbar.Create(this));if(this.showColumns)
|
||||
{var div=this.CreateElement('div');var columns=this.CreateElement('div');var showEvery=10;var i=1;while(i<=150)
|
||||
{if(i%showEvery==0)
|
||||
{div.innerHTML+=i;i+=(i+'').length;}
|
||||
else
|
||||
{div.innerHTML+='·';i++;}}
|
||||
columns.className='columns';columns.appendChild(div);this.bar.appendChild(columns);}
|
||||
for(var i=0,lineIndex=this.firstLine;i<lines.length-1;i++,lineIndex++)
|
||||
{var li=this.CreateElement('LI');var span=this.CreateElement('SPAN');li.className=(i%2==0)?'alt':'';span.innerHTML=lines[i]+' ';li.appendChild(span);this.ol.appendChild(li);}
|
||||
this.div.innerHTML='';}
|
||||
dp.sh.Highlighter.prototype.Highlight=function(code)
|
||||
{function Trim(str)
|
||||
{return str.replace(/^\s*(.*?)[\s\n]*$/g,'$1');}
|
||||
function Chop(str)
|
||||
{return str.replace(/\n*$/,'').replace(/^\n*/,'');}
|
||||
function Unindent(str)
|
||||
{var lines=dp.sh.Utils.FixForBlogger(str).split('\n');var indents=new Array();var regex=new RegExp('^\\s*','g');var min=1000;for(var i=0;i<lines.length&&min>0;i++)
|
||||
{if(Trim(lines[i]).length==0)
|
||||
continue;var matches=regex.exec(lines[i]);if(matches!=null&&matches.length>0)
|
||||
min=Math.min(matches[0].length,min);}
|
||||
if(min>0)
|
||||
for(var i=0;i<lines.length;i++)
|
||||
lines[i]=lines[i].substr(min);return lines.join('\n');}
|
||||
function Copy(string,pos1,pos2)
|
||||
{return string.substr(pos1,pos2-pos1);}
|
||||
var pos=0;if(code==null)
|
||||
code='';this.originalCode=code;this.code=Chop(Unindent(code));this.div=this.CreateElement('DIV');this.bar=this.CreateElement('DIV');this.ol=this.CreateElement('OL');this.matches=new Array();this.div.className='dp-highlighter';this.div.highlighter=this;this.bar.className='bar';this.ol.start=this.firstLine;if(this.CssClass!=null)
|
||||
this.ol.className=this.CssClass;if(this.collapse)
|
||||
this.div.className+=' collapsed';if(this.noGutter)
|
||||
this.div.className+=' nogutter';if(this.tabsToSpaces==true)
|
||||
this.code=this.ProcessSmartTabs(this.code);this.ProcessRegexList();if(this.matches.length==0)
|
||||
{this.AddBit(this.code,null);this.SwitchToList();this.div.appendChild(this.bar);this.div.appendChild(this.ol);return;}
|
||||
this.matches=this.matches.sort(dp.sh.Highlighter.SortCallback);for(var i=0;i<this.matches.length;i++)
|
||||
if(this.IsInside(this.matches[i]))
|
||||
this.matches[i]=null;for(var i=0;i<this.matches.length;i++)
|
||||
{var match=this.matches[i];if(match==null||match.length==0)
|
||||
continue;this.AddBit(Copy(this.code,pos,match.index),null);this.AddBit(match.value,match.css);pos=match.index+match.length;}
|
||||
this.AddBit(this.code.substr(pos),null);this.SwitchToList();this.div.appendChild(this.bar);this.div.appendChild(this.ol);}
|
||||
dp.sh.Highlighter.prototype.GetKeywords=function(str)
|
||||
{return'\\b'+str.replace(/ /g,'\\b|\\b')+'\\b';}
|
||||
dp.sh.BloggerMode=function()
|
||||
{dp.sh.isBloggerMode=true;}
|
||||
dp.sh.HighlightAll=function(name,showGutter,showControls,collapseAll,firstLine,showColumns)
|
||||
{function FindValue()
|
||||
{var a=arguments;for(var i=0;i<a.length;i++)
|
||||
{if(a[i]==null)
|
||||
continue;if(typeof(a[i])=='string'&&a[i]!='')
|
||||
return a[i]+'';if(typeof(a[i])=='object'&&a[i].value!='')
|
||||
return a[i].value+'';}
|
||||
return null;}
|
||||
function IsOptionSet(value,list)
|
||||
{for(var i=0;i<list.length;i++)
|
||||
if(list[i]==value)
|
||||
return true;return false;}
|
||||
function GetOptionValue(name,list,defaultValue)
|
||||
{var regex=new RegExp('^'+name+'\\[(\\w+)\\]$','gi');var matches=null;for(var i=0;i<list.length;i++)
|
||||
if((matches=regex.exec(list[i]))!=null)
|
||||
return matches[1];return defaultValue;}
|
||||
function FindTagsByName(list,name,tagName)
|
||||
{var tags=document.getElementsByTagName(tagName);for(var i=0;i<tags.length;i++)
|
||||
if(tags[i].getAttribute('name')==name)
|
||||
list.push(tags[i]);}
|
||||
var elements=[];var highlighter=null;var registered={};var propertyName='innerHTML';FindTagsByName(elements,name,'pre');FindTagsByName(elements,name,'textarea');if(elements.length==0)
|
||||
return;for(var brush in dp.sh.Brushes)
|
||||
{var aliases=dp.sh.Brushes[brush].Aliases;if(aliases==null)
|
||||
continue;for(var i=0;i<aliases.length;i++)
|
||||
registered[aliases[i]]=brush;}
|
||||
for(var i=0;i<elements.length;i++)
|
||||
{var element=elements[i];var options=FindValue(element.attributes['class'],element.className,element.attributes['language'],element.language);var language='';if(options==null)
|
||||
continue;options=options.split(':');language=options[0].toLowerCase();if(registered[language]==null)
|
||||
continue;highlighter=new dp.sh.Brushes[registered[language]]();element.style.display='none';highlighter.noGutter=(showGutter==null)?IsOptionSet('nogutter',options):!showGutter;highlighter.addControls=(showControls==null)?!IsOptionSet('nocontrols',options):showControls;highlighter.collapse=(collapseAll==null)?IsOptionSet('collapse',options):collapseAll;highlighter.showColumns=(showColumns==null)?IsOptionSet('showcolumns',options):showColumns;var headNode=document.getElementsByTagName('head')[0];if(highlighter.Style&&headNode)
|
||||
{var styleNode=document.createElement('style');styleNode.setAttribute('type','text/css');if(styleNode.styleSheet)
|
||||
{styleNode.styleSheet.cssText=highlighter.Style;}
|
||||
else
|
||||
{var textNode=document.createTextNode(highlighter.Style);styleNode.appendChild(textNode);}
|
||||
headNode.appendChild(styleNode);}
|
||||
highlighter.firstLine=(firstLine==null)?parseInt(GetOptionValue('firstline',options,1)):firstLine;highlighter.Highlight(element[propertyName]);highlighter.source=element;element.parentNode.insertBefore(highlighter.div,element);}}
|
Binary file not shown.
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 390 B |
BIN
htdocs/okapi/static/tilemap/rating_grin_small.png
Normal file
BIN
htdocs/okapi/static/tilemap/rating_grin_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 251 B |
BIN
htdocs/okapi/static/tilemap/rating_star_small.png
Normal file
BIN
htdocs/okapi/static/tilemap/rating_star_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 464 B |
@@ -31,3 +31,5 @@ class OkapiUrls
|
||||
// '^tilestress$' => 'tilestress',
|
||||
);
|
||||
}
|
||||
|
||||
# This line is used for commit-hooks testing: .........>
|
||||
|
@@ -115,7 +115,7 @@ class View
|
||||
$etag_hits = $calls['B'] - $calls['C'];
|
||||
|
||||
print "\n";
|
||||
print " $etag_hits of the requests matched the ETag and were served a HTTP 304 response.\n";
|
||||
print " $etag_hits of the requests matched the ETag and were served an HTTP 304 response.\n";
|
||||
print "\n";
|
||||
|
||||
$calls_left = $calls['C'];
|
||||
|
@@ -4,20 +4,17 @@
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<title>OKAPI Examples</title>
|
||||
<link rel="stylesheet" href="<?= $vars['okapi_base_url'] ?>static/common.css?<?= $vars['okapi_rev'] ?>">
|
||||
<link type="text/css" rel="stylesheet" href="<?= $vars['okapi_base_url'] ?>static/syntax_highlighter/SyntaxHighlighter.css"></link>
|
||||
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js'></script>
|
||||
<script>
|
||||
var okapi_base_url = "<?= $vars['okapi_base_url'] ?>";
|
||||
</script>
|
||||
<script src='<?= $vars['okapi_base_url'] ?>static/common.js?<?= $vars['okapi_rev'] ?>'></script>
|
||||
<script language="javascript" src="<?= $vars['okapi_base_url'] ?>static/syntax_highlighter/shCore.js"></script>
|
||||
<script language="javascript" src="<?= $vars['okapi_base_url'] ?>static/syntax_highlighter/shBrushPhp.js"></script>
|
||||
<script language="javascript">
|
||||
$(function() {
|
||||
dp.SyntaxHighlighter.ClipboardSwf = '<?= $vars['okapi_base_url'] ?>static/syntax_highlighter/clipboard.swf';
|
||||
dp.SyntaxHighlighter.HighlightAll('code');
|
||||
$('h2').each(function() {
|
||||
$('#toc').append($("<div></div>").append($("<a></a>")
|
||||
.text($(this).text()).attr("href", "#" + $(this).attr('id'))));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script src='<?= $vars['okapi_base_url'] ?>static/common.js?<?= $vars['okapi_rev'] ?>'></script>
|
||||
</head>
|
||||
<body class='api'>
|
||||
<div class='okd_mid'>
|
||||
@@ -29,11 +26,20 @@
|
||||
</td>
|
||||
<td class='article'>
|
||||
|
||||
<h1>Examples and libraries</h1>
|
||||
<h1>Examples, libraries and tools</h1>
|
||||
|
||||
<p>Here you will find basic examples of OKAPI usage with popular programming languages.</p>
|
||||
<div id='toc'></div>
|
||||
|
||||
<h2>Are there any client libraries?</h2>
|
||||
<h2 id='tools'>Tools</h2>
|
||||
|
||||
If you're just getting to know OKAPI, you might want to check out
|
||||
<a href='https://github.com/wrygiel/okapi-browser'>OKAPI Browser</a>
|
||||
(<a href='https://raw.github.com/wrygiel/okapi-browser/master/extras/screenshot.png'>screenshot</a>),
|
||||
a basic OAuth Console for OKAPI methods. It is an open-source project. You can
|
||||
<a href='https://github.com/wrygiel/okapi-browser'>fork it</a> on GitHub or simply
|
||||
<a href='http://usosphp.mimuw.edu.pl/~rygielski/okapi-browser/'>install it here</a>.
|
||||
|
||||
<h2 id='libraries'>Are there any client libraries?</h2>
|
||||
|
||||
<p>OKAPI <b>does not</b> require you to use any special libraries, usually you will want to
|
||||
use OKAPI "as is", via basic HTTP requests and responses.</p>
|
||||
@@ -53,65 +59,23 @@ protocol might be the safest choice.</p>
|
||||
|
||||
<div class='issue-comments' issue_id='96'></div>
|
||||
|
||||
<h2>PHP Example</h2>
|
||||
<h2 id='php1'>PHP Example 1 - simple query</h2>
|
||||
|
||||
<p><b>Example 1.</b> This will print the number of users in the <?= $vars['site_name'] ?> installation:
|
||||
|
||||
<pre name="code" class="php:nogutter:nocontrols">
|
||||
<?
|
||||
|
||||
$json = file_get_contents("<?= $vars['okapi_base_url'] ?>services/apisrv/stats");
|
||||
$data = json_decode($json);
|
||||
print "Number of <?= $vars['site_name'] ?> users: ".$data->user_count;
|
||||
|
||||
?>
|
||||
</pre>
|
||||
|
||||
<p><b>Example 2.</b> This will print the codes of some nearest unfound caches:</p>
|
||||
|
||||
<pre name="code" class="php:nogutter:nocontrols">
|
||||
<?
|
||||
|
||||
/* Enter your OKAPI's URL here. */
|
||||
$okapi_base_url = "http://opencaching.pl/okapi/";
|
||||
|
||||
/* Enter your Consumer Key here. */
|
||||
$consumer_key = "YOUR_KEY_HERE";
|
||||
|
||||
/* Username. Caches found by the given user will be excluded from the results. */
|
||||
$username = "USERNAME_HERE";
|
||||
|
||||
/* Your location. */
|
||||
$lat = 54.3;
|
||||
$lon = 22.3;
|
||||
|
||||
/* 1. Get the UUID of the user. */
|
||||
$json = @file_get_contents($okapi_base_url."services/users/by_username".
|
||||
"?username=".$username."&fields=uuid&consumer_key=".$consumer_key);
|
||||
if (!$json)
|
||||
die("ERROR! Check your consumer_key and/or username!\n");
|
||||
$user_uuid = json_decode($json)->uuid;
|
||||
print "Your UUID: ".$user_uuid."\n";
|
||||
|
||||
/* 2. Search for caches. */
|
||||
$json = @file_get_contents($okapi_base_url."services/caches/search/nearest".
|
||||
"?center=".$lat."|".$lon."&not_found_by=".$user_uuid."&limit=5".
|
||||
"&consumer_key=".$consumer_key);
|
||||
if (!$json)
|
||||
die("ERROR!");
|
||||
$cache_codes = json_decode($json)->results;
|
||||
|
||||
/* Display them. */
|
||||
print "Five nearest unfound caches: ".implode(", ", $cache_codes)."\n";
|
||||
|
||||
?>
|
||||
</pre>
|
||||
|
||||
<p>Please note that the above examples use very simple error checking routines.
|
||||
<p>Please note that the examples below use very simple error checking routines.
|
||||
If you want to be "professional", you should catch HTTP 400 Responses, read their
|
||||
bodies (OKAPI error messages), and deal with them more gracefully.</p>
|
||||
|
||||
<h2>JavaScript Example</h2>
|
||||
<p>This will print the number of users in the <?= $vars['site_name'] ?> installation:
|
||||
|
||||
<script src="https://gist.github.com/4231796.js?file=users.php"></script>
|
||||
|
||||
<h2 id='php2'>PHP Example 2 - search for nearest geocaches</h2>
|
||||
|
||||
<p>This will print the codes of some nearest unfound caches:</p>
|
||||
|
||||
<script src="https://gist.github.com/4231824.js?file=nearest_unfound.php"></script>
|
||||
|
||||
<h2 id='js1'>JavaScript Example</h2>
|
||||
|
||||
<p>It is possible to access OKAPI directly from user's browser, without the
|
||||
need for server backend. OKAPI allows <a href='http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests'>Cross-domain
|
||||
@@ -129,7 +93,17 @@ There are some limitations of both these techniques though.</p>
|
||||
|
||||
<p><a href='<?= $vars['okapi_base_url'] ?>static/examples/javascript_nearest.html' style='font-size: 130%; font-weight: bold'>Run this example</a></p>
|
||||
|
||||
<h2>Comments</h2>
|
||||
<h2 id='cs1'>C# Example</h2>
|
||||
|
||||
<p><a href='https://github.com/wrygiel/okapi-browser'>OKAPI Browser</a>
|
||||
(already mentioned in the Tools section) is an open-source project. Written in C#.NET, uses
|
||||
the <a href='<?= $vars['okapi_base_url'] ?>services/apisrv/installations.html'>apisrv</a>
|
||||
and <a href='<?= $vars['okapi_base_url'] ?>services/apiref/method_index.html'>apiref</a>
|
||||
modules to dynamically retrieve the current list of OKAPI installations and methods.
|
||||
<a href='https://github.com/wrygiel/okapi-browser'>Get the source</a> or
|
||||
<a href='http://usosphp.mimuw.edu.pl/~rygielski/okapi-browser/'>try it</a> first.</p>
|
||||
|
||||
<h2 id='comments'>Comments</h2>
|
||||
|
||||
<div class='issue-comments' issue_id='36'></div>
|
||||
|
||||
|
@@ -18,7 +18,7 @@
|
||||
Page Not Found
|
||||
<div class='subh1'>:: 404 Error</div>
|
||||
</h1>
|
||||
<p>The page you requested does not exist. Try one of the page in the side menu!</p>
|
||||
<p>The page you requested does not exist. Try one of the pages in the side menu!</p>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
|
@@ -148,7 +148,7 @@ parameters required for the method to run):</p>
|
||||
<li><b>jsonp</b> - <a href='http://en.wikipedia.org/wiki/JSONP'>JSONP</a> format, if
|
||||
you choose this one, you have to specify the <b>callback</b> parameter,</li>
|
||||
<li class='deprecated'><b>xmlmap</b> - deprecated (<a href='http://code.google.com/p/opencaching-api/issues/detail?id=128'>why?</a>),</li>
|
||||
<li><b>xmlmap2</b> - XML format. This is produced by mapping JSON datatypes to XML elements.
|
||||
<li><b>xmlmap2</b> - XML format. This is produced by mapping JSON data types to XML elements.
|
||||
Keep in mind, that XML format is larger than JSON and it takes more time to generate
|
||||
and parse. Try to use JSON when it's possible.</li>
|
||||
</ul>
|
||||
@@ -159,12 +159,12 @@ parameters required for the method to run):</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p><b><u>Important:</u></b> Almost all of the returned datatypes are <b>extendible</b>. This means,
|
||||
<p><b><u>Important:</u></b> Almost all of the returned data types are <b>extendible</b>. This means,
|
||||
that (in future) they <b>may contain data that currently they don't</b>.
|
||||
Such data will be included in backward-compatible manner, but still you should remember about
|
||||
it in some cases (i.e. when iterating over attributes of an object). This additional data may
|
||||
appear as extra elements in GPX files or extra keys in JSON responses.
|
||||
Your software <b>must ignore</b> such occurances if it doesn't understand them!</p>
|
||||
Your software <b>must ignore</b> such occurrences if it doesn't understand them!</p>
|
||||
|
||||
<p>Some methods expose some <b>special formatting</b> of their own, for example, they may return
|
||||
a JPEG or a GPX file. Such methods do not accept <i>common formatting parameters</i>.</p>
|
||||
@@ -192,7 +192,7 @@ method calls and redirects which provide you with an Access Token).</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Things you should pay attantion to:</p>
|
||||
<p>Things you should pay attention to:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>The <b>oauth_callback</b> argument of the <b>request_token</b> method is <b>required</b>.</p>
|
||||
|
@@ -16,9 +16,9 @@ use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use okapi\Settings;
|
||||
use okapi\OkapiLock;
|
||||
|
||||
use okapi\cronjobs\CronJobController;
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/cronjobs.php");
|
||||
|
||||
class View
|
||||
{
|
||||
@@ -622,4 +622,32 @@ class View
|
||||
private static function ver74() { Db::execute("update okapi_cache set score=1, expires=date_add(now(), interval 360 day) where `key` like 'tilecaption/%'"); }
|
||||
private static function ver75() { Db::execute("alter table okapi_cache modify column score float default null"); }
|
||||
private static function ver76() { Db::execute("update okapi_cache set expires=date_add(now(), interval 100 year) where `key` like 'clog#geocache#%'"); }
|
||||
|
||||
private static function ver77()
|
||||
{
|
||||
Db::execute("
|
||||
CREATE TABLE okapi_search_sets (
|
||||
id mediumint(6) unsigned not null auto_increment,
|
||||
params_hash varchar(64) not null,
|
||||
primary key (id),
|
||||
key by_hash (params_hash, id)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
private static function ver78()
|
||||
{
|
||||
Db::execute("
|
||||
CREATE TABLE okapi_search_results (
|
||||
set_id mediumint(6) unsigned not null,
|
||||
cache_id mediumint(6) unsigned not null,
|
||||
primary key (set_id, cache_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
private static function ver79() { Db::execute("alter table okapi_search_results engine=MyISAM"); }
|
||||
private static function ver80() { Db::execute("alter table okapi_search_sets add column date_created datetime not null"); }
|
||||
private static function ver81() { Db::execute("alter table okapi_search_sets add column expires datetime not null"); }
|
||||
private static function ver82() { CronJobController::reset_job_schedule("FulldumpGeneratorJob"); }
|
||||
}
|
||||
|
Reference in New Issue
Block a user