okapi r651
This commit is contained in:
@ -10,7 +10,7 @@ use okapi\views\menu\OkapiMenu;
|
||||
#
|
||||
# All HTTP requests within the /okapi/ path are redirected through this
|
||||
# controller. From here we'll pass them to the right entry point (or
|
||||
# display an appropriate error message).
|
||||
# display an appropriate error message).
|
||||
#
|
||||
# To learn more about OKAPI, see core.php.
|
||||
#
|
||||
@ -26,7 +26,7 @@ if (ob_list_handlers() == array('default output handler'))
|
||||
# We will assume that this one comes from "output_buffering" being turned on
|
||||
# in PHP config. This is very common and probably is good for most other OC
|
||||
# pages. But we don't need it in OKAPI. We will just turn this off.
|
||||
|
||||
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
@ -36,32 +36,32 @@ class OkapiScriptEntryPointController
|
||||
public static function dispatch_request($uri)
|
||||
{
|
||||
# Chop off the ?args=... part.
|
||||
|
||||
|
||||
if (strpos($uri, '?') !== false)
|
||||
$uri = substr($uri, 0, strpos($uri, '?'));
|
||||
|
||||
|
||||
# Chop off everything before "/okapi/". This should work for okay for most "weird"
|
||||
# server configurations. It will also address a more subtle issue described here:
|
||||
# http://stackoverflow.com/questions/8040461/request-uri-unexpectedly-contains-fqdn
|
||||
|
||||
|
||||
if (strpos($uri, "/okapi/") !== false)
|
||||
$uri = substr($uri, strpos($uri, "/okapi/"));
|
||||
|
||||
|
||||
# Make sure we're in the right directory (.htaccess should make sure of that).
|
||||
|
||||
|
||||
if (strpos($uri, "/okapi/") !== 0)
|
||||
throw new Exception("'$uri' is outside of the /okapi/ path.");
|
||||
$uri = substr($uri, 7);
|
||||
|
||||
|
||||
# Initializing internals and running pre-request cronjobs (we don't want
|
||||
# cronjobs to be run before "okapi/update", for example before database
|
||||
# was installed).
|
||||
|
||||
|
||||
$allow_cronjobs = ($uri != "update");
|
||||
Okapi::init_internals($allow_cronjobs);
|
||||
|
||||
|
||||
# Checking for allowed patterns...
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
foreach (OkapiUrls::$mapping as $pattern => $namespace)
|
||||
@ -70,7 +70,7 @@ class OkapiScriptEntryPointController
|
||||
if (preg_match("#$pattern#", $uri, $matches))
|
||||
{
|
||||
# Pattern matched! Moving on to the proper View...
|
||||
|
||||
|
||||
array_shift($matches);
|
||||
require_once($GLOBALS['rootpath']."okapi/views/$namespace.php");
|
||||
$response = call_user_func_array(array('\\okapi\\views\\'.
|
||||
@ -85,9 +85,9 @@ class OkapiScriptEntryPointController
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
|
||||
# None of the patterns matched OR method threw the Http404 exception.
|
||||
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/views/http404.php");
|
||||
$response = \okapi\views\http404\View::call();
|
||||
$response->display();
|
||||
|
@ -291,9 +291,11 @@ class ParamMissing extends BadRequest
|
||||
/** Common type of BadRequest: Parameter has invalid value. */
|
||||
class InvalidParam extends BadRequest
|
||||
{
|
||||
private $paramName;
|
||||
public $paramName;
|
||||
|
||||
/** What was wrong about the param? */
|
||||
public $whats_wrong_about_it;
|
||||
|
||||
protected function provideExtras(&$extras) {
|
||||
parent::provideExtras($extras);
|
||||
$extras['reason_stack'][] = 'invalid_parameter';
|
||||
@ -419,6 +421,23 @@ class Db
|
||||
}
|
||||
return $rs;
|
||||
}
|
||||
|
||||
public static function field_exists($table, $field)
|
||||
{
|
||||
if (!preg_match("/[a-z0-9_]+/", $table.$field))
|
||||
return false;
|
||||
try {
|
||||
$spec = self::select_all("desc ".$table.";");
|
||||
} catch (Exception $e) {
|
||||
/* Table doesn't exist, probably. */
|
||||
return false;
|
||||
}
|
||||
foreach ($spec as &$row_ref) {
|
||||
if (strtoupper($row_ref['Field']) == strtoupper($field))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
@ -670,7 +689,7 @@ class OkapiHttpResponse
|
||||
if ($try_gzip && is_string($this->body))
|
||||
{
|
||||
header("Content-Encoding: gzip");
|
||||
$gzipped = gzencode($this->body, 5, true);
|
||||
$gzipped = gzencode($this->body, 5);
|
||||
header("Content-Length: ".strlen($gzipped));
|
||||
print $gzipped;
|
||||
}
|
||||
@ -759,7 +778,7 @@ class Okapi
|
||||
{
|
||||
public static $data_store;
|
||||
public static $server;
|
||||
public static $revision = 556; # This gets replaced in automatically deployed packages
|
||||
public static $revision = 651; # 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. */
|
||||
@ -1957,7 +1976,7 @@ class OkapiHttpRequest extends OkapiRequest
|
||||
|
||||
if (!Settings::get('DEBUG'))
|
||||
{
|
||||
throw new Exception("Attempted to set DEBUG_AS_USERNAME set in ".
|
||||
throw new Exception("Attempted to use DEBUG_AS_USERNAME in ".
|
||||
"non-debug environment. Accidental commit?");
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use okapi\OkapiInternalConsumer;
|
||||
use okapi\services\replicate\ReplicateCommon;
|
||||
use okapi\services\attrs\AttrHelper;
|
||||
|
||||
class CronJobController
|
||||
{
|
||||
@ -50,6 +51,7 @@ class CronJobController
|
||||
new FulldumpGeneratorJob(),
|
||||
new TileTreeUpdater(),
|
||||
new SearchSetsCleanerJob(),
|
||||
new AttrsRefresherJob(),
|
||||
);
|
||||
foreach ($cache as $cronjob)
|
||||
if (!in_array($cronjob->get_type(), array('pre-request', 'cron-5')))
|
||||
@ -57,7 +59,7 @@ class CronJobController
|
||||
}
|
||||
return $cache;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute all scheduled cronjobs of given type, reschedule, and return
|
||||
* UNIX timestamp of the nearest scheduled event.
|
||||
@ -65,7 +67,7 @@ class CronJobController
|
||||
public static function run_jobs($type)
|
||||
{
|
||||
require_once($GLOBALS['rootpath'].'okapi/service_runner.php');
|
||||
|
||||
|
||||
# We don't want other cronjobs of the same time to run simultanously.
|
||||
$lock = OkapiLock::get('cronjobs-'.$type);
|
||||
$lock->acquire();
|
||||
@ -99,9 +101,9 @@ class CronJobController
|
||||
Cache::set("cron_schedule", $schedule, 30*86400);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Remove "stale" schedule keys (those which are no longer declared).
|
||||
|
||||
|
||||
$fixed_schedule = array();
|
||||
foreach (self::get_enabled_cronjobs() as $cronjob)
|
||||
{
|
||||
@ -109,9 +111,9 @@ class CronJobController
|
||||
$fixed_schedule[$name] = $schedule[$name];
|
||||
}
|
||||
unset($schedule);
|
||||
|
||||
|
||||
# Return the nearest scheduled event time.
|
||||
|
||||
|
||||
$nearest = time() + 3600;
|
||||
foreach ($fixed_schedule as $name => $time)
|
||||
if ($time < $nearest)
|
||||
@ -120,7 +122,7 @@ class CronJobController
|
||||
$lock->release();
|
||||
return $nearest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Force a specified cronjob to run. Throw an exception if cronjob not found.
|
||||
* $job_name mast equal one of the names returned by ->get_name() method.
|
||||
@ -128,7 +130,7 @@ class CronJobController
|
||||
public static function force_run($job_name)
|
||||
{
|
||||
require_once($GLOBALS['rootpath'].'okapi/service_runner.php');
|
||||
|
||||
|
||||
foreach (self::get_enabled_cronjobs() as $cronjob)
|
||||
{
|
||||
if (($cronjob->get_name() == $job_name) || ($cronjob->get_name() == "okapi\\cronjobs\\".$job_name))
|
||||
@ -139,7 +141,7 @@ class CronJobController
|
||||
}
|
||||
throw new Exception("CronJob $job_name not found.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset the schedule of a specified cronjob. This will force the job to
|
||||
* run on nearest occasion (but not NOW).
|
||||
@ -152,10 +154,10 @@ class CronJobController
|
||||
$thejob = $tmp;
|
||||
if ($thejob == null)
|
||||
throw new Exception("Could not reset schedule for job $job_name. $jon_name not found.");
|
||||
|
||||
|
||||
# We have to acquire lock on the schedule. This might take some time if cron-5 jobs are
|
||||
# currently being run.
|
||||
|
||||
|
||||
$type = $thejob->get_type();
|
||||
$lock = OkapiLock::get('cronjobs-'.$type);
|
||||
$lock->acquire();
|
||||
@ -167,7 +169,7 @@ class CronJobController
|
||||
unset($schedule[$thejob->get_name()]);
|
||||
Cache::set("cron_schedule", $schedule, 30*86400);
|
||||
}
|
||||
|
||||
|
||||
$lock->release();
|
||||
}
|
||||
}
|
||||
@ -176,10 +178,10 @@ abstract class CronJob
|
||||
{
|
||||
/** Run the job. */
|
||||
public abstract function execute();
|
||||
|
||||
|
||||
/** Get unique name for this cronjob. */
|
||||
public function get_name() { return get_class($this); }
|
||||
|
||||
|
||||
/**
|
||||
* Get the type of this cronjob. Currently there are two: 'pre-request'
|
||||
* and 'cron-5'. The first can be executed before every request, the second
|
||||
@ -189,7 +191,7 @@ abstract class CronJob
|
||||
* (before 'cron-5' runs).
|
||||
*/
|
||||
public abstract function get_type();
|
||||
|
||||
|
||||
/**
|
||||
* Get the next scheduled run (unix timestamp). You may assume this function
|
||||
* will be called ONLY directly after the job was run. You may use this to say,
|
||||
@ -211,12 +213,12 @@ abstract class PrerequestCronJob extends CronJob
|
||||
*/
|
||||
public final function get_type() { return 'pre-request'; }
|
||||
|
||||
/**
|
||||
/**
|
||||
* Return number of seconds - a *minimum* time period that should pass between
|
||||
* running the job.
|
||||
*/
|
||||
public abstract function get_period();
|
||||
|
||||
|
||||
public function get_next_scheduled_run($previously_scheduled_run)
|
||||
{
|
||||
return time() + $this->get_period();
|
||||
@ -233,13 +235,13 @@ abstract class Cron5Job extends CronJob
|
||||
* Always returns 'cron-5'.
|
||||
*/
|
||||
public final function get_type() { return 'cron-5'; }
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Return number of seconds - period of time after which cronjob execution
|
||||
* should be repeated. This should be dividable be 300 (5 minutes).
|
||||
*/
|
||||
public abstract function get_period();
|
||||
|
||||
|
||||
public function get_next_scheduled_run($previously_scheduled_run)
|
||||
{
|
||||
$t = time() + $this->get_period();
|
||||
@ -287,23 +289,23 @@ class CacheCleanupCronJob extends Cron5Job
|
||||
public function execute()
|
||||
{
|
||||
# Delete all expired elements.
|
||||
|
||||
|
||||
Db::execute("
|
||||
delete from okapi_cache
|
||||
where expires < now()
|
||||
");
|
||||
|
||||
|
||||
# Update the "score" stats.
|
||||
|
||||
|
||||
$multiplier = 0.9; # Every hour, all scores are multiplied by this.
|
||||
$limit = 0.01; # When a score reaches this limit, the entry is deleted.
|
||||
|
||||
|
||||
# Every time the entry is read, its score is incread by 1. If an entry
|
||||
# is saved, but never read, it will be deleted after log(L,M) hours
|
||||
# (log(0.01, 0.9) = 43h). If an entry is read 1000000 times and then
|
||||
# never read anymore, it will be deleted after log(1000000/L, 1/M)
|
||||
# hours (log(1000000/0.01, 1/0.9) = 174h = 7 days).
|
||||
|
||||
|
||||
Db::execute("
|
||||
update okapi_cache
|
||||
set score = score * $multiplier
|
||||
@ -323,10 +325,10 @@ class CacheCleanupCronJob extends Cron5Job
|
||||
and c.score is not null
|
||||
");
|
||||
Db::execute("truncate okapi_cache_reads");
|
||||
|
||||
|
||||
# Delete elements with the lowest score. Entries which have been set
|
||||
# but never read will be removed after 36 hours (0.9^36 < 0.02 < 0.9^35).
|
||||
|
||||
|
||||
Db::execute("
|
||||
delete from okapi_cache
|
||||
where
|
||||
@ -334,10 +336,10 @@ class CacheCleanupCronJob extends Cron5Job
|
||||
and score < $limit
|
||||
");
|
||||
Db::query("optimize table okapi_cache");
|
||||
|
||||
|
||||
# FileCache does not have an expiry date. We will delete all files older
|
||||
# than 24 hours.
|
||||
|
||||
|
||||
$dir = Okapi::get_var_dir();
|
||||
if ($dh = opendir($dir)) {
|
||||
while (($file = readdir($dh)) !== false) {
|
||||
@ -431,13 +433,13 @@ 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', 5, 86400);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
# There was no ping. Decrement the counter. When reached zero, alert.
|
||||
|
||||
|
||||
$counter = Cache::get('crontab_check_counter');
|
||||
if ($counter === null)
|
||||
$counter = 5;
|
||||
@ -458,10 +460,10 @@ class CheckCronTab2 extends PrerequestCronJob
|
||||
"ignore it. Probably you just paused (or switched off) your VM for some time\n".
|
||||
"(which would be considered an error in production environment)."
|
||||
);
|
||||
|
||||
|
||||
# Schedule the next admin-nagging. Each subsequent notification will be sent
|
||||
# with a greater delay.
|
||||
|
||||
|
||||
$since_last = time() - $last_ping;
|
||||
Cache::set('crontab_check_counter', (int)($since_last / $this->get_period()), 86400);
|
||||
}
|
||||
@ -537,13 +539,13 @@ class TileTreeUpdater extends Cron5Job
|
||||
if (!$response['more'])
|
||||
break;
|
||||
} catch (BadRequest $e) {
|
||||
# Invalid 'since' parameter? May happen whne crontab was
|
||||
# Invalid 'since' parameter? May happen when crontab was
|
||||
# not working for more than 10 days. Or, just after OKAPI
|
||||
# is installed (and this is the first time this cronjob
|
||||
# if being run).
|
||||
|
||||
|
||||
$mail_admins = ($tiletree_revision > 0);
|
||||
\okapi\services\caches\map\ReplicateListener::reset($mail_admins);
|
||||
\okapi\services\caches\map\ReplicateListener::reset();
|
||||
Okapi::set_var('clog_followup_revision', $current_clog_revision);
|
||||
break;
|
||||
}
|
||||
@ -702,21 +704,21 @@ class AdminStatsSender extends Cron5Job
|
||||
print str_pad($row['users'], 8, " ", STR_PAD_LEFT)."\n";
|
||||
}
|
||||
print "\n";
|
||||
|
||||
|
||||
print "This report includes requests from external consumers and those made via\n";
|
||||
print "Facade class (used by OC code). It does not include methods used by OKAPI\n";
|
||||
print "internally (i.e. while running cronjobs). Runtimes do not include HTTP\n";
|
||||
print "request handling overhead.\n";
|
||||
|
||||
|
||||
$message = ob_get_clean();
|
||||
Okapi::mail_admins("Weekly OKAPI usage report", $message);
|
||||
}
|
||||
|
||||
|
||||
private static function mb_str_pad($input, $pad_length, $pad_string, $pad_style)
|
||||
{
|
||||
{
|
||||
return str_pad($input, strlen($input) - mb_strlen($input) + $pad_length,
|
||||
$pad_string, $pad_style);
|
||||
}
|
||||
$pad_string, $pad_style);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -773,3 +775,17 @@ class LocaleChecker extends Cron5Job
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Once every hour, update the official cache attributes listing.
|
||||
*
|
||||
* WRTODO: Make it 12 hours later.
|
||||
*/
|
||||
class AttrsRefresherJob extends Cron5Job
|
||||
{
|
||||
public function get_period() { return 3600; }
|
||||
public function execute()
|
||||
{
|
||||
require_once($GLOBALS['rootpath']."okapi/services/attrs/attr_helper.inc.php");
|
||||
AttrHelper::refresh_if_stale();
|
||||
}
|
||||
}
|
||||
|
@ -4,22 +4,23 @@ namespace okapi;
|
||||
|
||||
# OKAPI Framework -- Wojciech Rygielski <rygielski@mimuw.edu.pl>
|
||||
|
||||
# Include this file if you want to use OKAPI's services with any
|
||||
# external code (your service calls will appear under the name "Facade"
|
||||
# in the weekly OKAPI usage report).
|
||||
# Use this class when you want to use OKAPI's services within OC code.
|
||||
# (Your service calls will appear with the name "Facade" in the weekly
|
||||
# OKAPI usage report).
|
||||
|
||||
# Note, that his is the *ONLY* internal OKAPI file that is guaranteed
|
||||
# to stay backward-compatible (I'm speaking about INTERNAL files here,
|
||||
# all OKAPI methods will stay compatible forever). If you want to use
|
||||
# something that has not been exposed through the Facade class, contact
|
||||
# IMPORTANT COMPATIBILITY NOTES:
|
||||
|
||||
# Note, that this is the *ONLY* internal OKAPI file that is guaranteed
|
||||
# to stay backward-compatible (note that we mean FILES here, all OKAPI
|
||||
# methods will stay compatible forever). If you want to use any class or
|
||||
# method that has not been exposed through the Facade class, contact
|
||||
# OKAPI developers, we will add it here.
|
||||
|
||||
# Including this file will initialize OKAPI Framework with its default
|
||||
# exception and error handlers. OKAPI is strict about PHP warnings and
|
||||
# notices. You might need to temporarily disable the error handler in
|
||||
# order to get it to work with some legacy code. Do this by calling
|
||||
# OkapiErrorHandler::disable() BEFORE calling the "buggy" code, and
|
||||
# OkapiErrorHandler::reenable() AFTER returning from it.
|
||||
# notices, so you might need to temporarily disable the error handler in
|
||||
# order to get it to work with your code. Just call this after you
|
||||
# include the Facade file: OkapiErrorHandler::disable().
|
||||
|
||||
|
||||
use Exception;
|
||||
@ -54,7 +55,7 @@ class Facade
|
||||
$request->perceive_as_http_request = true;
|
||||
return OkapiServiceRunner::call($service_name, $request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This works like service_call with two exceptions: 1. It passes all your
|
||||
* current HTTP request headers to OKAPI (which can make use of them in
|
||||
@ -74,7 +75,7 @@ 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
|
||||
@ -98,4 +99,42 @@ class Facade
|
||||
$tables, $where_conds, $min_store, $max_ref_age
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the specified caches as *possibly* modified. The replicate module
|
||||
* will scan for changes within these caches on the next changelog update.
|
||||
* This is useful in some cases, when OKAPI cannot detect the modification
|
||||
* for itself (grep OCPL code for examples). See issue #179.
|
||||
*
|
||||
* $cache_codes may be a single cache code or an array of codes.
|
||||
*/
|
||||
public static function schedule_geocache_check($cache_codes)
|
||||
{
|
||||
if (!is_array($cache_codes))
|
||||
$cache_codes = array($cache_codes);
|
||||
Db::execute("
|
||||
update caches
|
||||
set okapi_syncbase = now()
|
||||
where wp_oc in ('".implode("','", array_map('mysql_real_escape_string', $cache_codes))."')
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* You will probably want to call that with FALSE when using Facade
|
||||
* in buggy, legacy OC code. This will disable OKAPI's default behavior
|
||||
* of treating NOTICEs as errors.
|
||||
*/
|
||||
public static function disable_error_handling()
|
||||
{
|
||||
OkapiErrorHandler::disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* If you disabled OKAPI's error handling with disable_error_handling,
|
||||
* you may reenable it with this method.
|
||||
*/
|
||||
public static function reenable_error_handling()
|
||||
{
|
||||
OkapiErrorHandler::reenable();
|
||||
}
|
||||
}
|
||||
|
@ -14,16 +14,16 @@ class OCSession
|
||||
static $cached_result = false;
|
||||
if ($cached_result !== false)
|
||||
return $cached_result;
|
||||
|
||||
|
||||
$cookie_name = Settings::get('OC_COOKIE_NAME');
|
||||
if (!isset($_COOKIE[$cookie_name]))
|
||||
return null;
|
||||
$OC_data = unserialize(base64_decode($_COOKIE[$cookie_name]));
|
||||
$OC_sessionid = $OC_data['sessionid'];
|
||||
|
||||
|
||||
if (!$OC_sessionid)
|
||||
return null;
|
||||
|
||||
|
||||
return Db::select_value("select user_id from sys_sessions where uuid='".mysql_real_escape_string($OC_sessionid)."'");
|
||||
}
|
||||
}
|
Binary file not shown.
@ -2,75 +2,95 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OKAPI\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-08-22 21:18+0100\n"
|
||||
"PO-Revision-Date: 2012-08-22 21:18+0100\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: following <following-okapi@online.de>\n"
|
||||
"POT-Creation-Date: 2013-03-30 23:41+0100\n"
|
||||
"PO-Revision-Date: 2013-03-30 23:42+0100\n"
|
||||
"Last-Translator: following <following@online.de>\n"
|
||||
"Language-Team: following <following@online.de>\n"
|
||||
"Language: German\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
|
||||
"X-Poedit-Basepath: c:\\source\\oc\\server-3.0\\htdocs\\okapi\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"X-Poedit-Basepath: c:\\source\\oc\\okapi\\following2\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Poedit-SearchPath-0: c:\\source\\oc\\server-3.0\\htdocs\\okapi\n"
|
||||
"X-Generator: Poedit 1.5.5\n"
|
||||
"X-Poedit-SearchPath-0: c:\\source\\oc\\okapi\\following2\n"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/geocaches.php:640
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/geocaches.php:817
|
||||
msgid "Stage"
|
||||
msgstr "Station"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:27
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:44
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/geocaches.php:950
|
||||
#, php-format
|
||||
msgid ""
|
||||
"<em>© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/de/deed.en'>CC-BY-NC-ND</a>, as of "
|
||||
"%s; all log entries © their authors</em>"
|
||||
msgstr ""
|
||||
"<em>© <a href='%s'>%s</a>, <a href='%s'>%s</a>, <a href='http://"
|
||||
"creativecommons.org/licenses/by-nc-nd/3.0/de/'>CC-BY-NC-ND</a>, Stand: %s; "
|
||||
"alle Logeinträge © jeweiliger Autor</em>"
|
||||
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/geocaches.php:960
|
||||
#, php-format
|
||||
msgid ""
|
||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||
"a> site."
|
||||
msgstr ""
|
||||
"Diese <a href='%s'>Cache</a>-Beschreibung stammt von <a href='%s'>%s</a>."
|
||||
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:31
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:48
|
||||
msgid "hidden by"
|
||||
msgstr "versteckt von"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:46
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:50
|
||||
#, php-format
|
||||
msgid "%d recommendation"
|
||||
msgid_plural "%d recommendations"
|
||||
msgstr[0] "%d Empfehlung"
|
||||
msgstr[1] "%d Empfehlungen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:47
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:51
|
||||
#, php-format
|
||||
msgid "found %d time"
|
||||
msgid_plural "found %d times"
|
||||
msgstr[0] "%d mal gefunden"
|
||||
msgstr[1] "%d mal gefunden"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:50
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:54
|
||||
#, php-format
|
||||
msgid "%d trackable"
|
||||
msgid_plural "%d trackables"
|
||||
msgstr[0] "%d Geokret"
|
||||
msgstr[1] "%d Geokrets"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:54
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:58
|
||||
msgid "Personal notes"
|
||||
msgstr "Persönliche Notizen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:58
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
msgid "Attributes"
|
||||
msgstr "Attribute"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:66
|
||||
msgid "Trackables"
|
||||
msgstr "Geokrets"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:80
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:84
|
||||
msgid "Images"
|
||||
msgstr "Bilder"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:87
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:91
|
||||
msgid "Spoilers"
|
||||
msgstr "Spoiler"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/caches/formatters/gpxfile.tpl.php:95
|
||||
#: c:\source\oc\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:99
|
||||
msgid "Image descriptions"
|
||||
msgstr "Bildbeschreibungen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:62
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:75
|
||||
msgid ""
|
||||
"You are trying to publish a log entry with a date in future. Cache log "
|
||||
"entries are allowed to be published in the past, but NOT in the future."
|
||||
@ -78,7 +98,7 @@ msgstr ""
|
||||
"Das Datum deines Logeintrags liegt in der Zukunft. Cache-Logs können nur für "
|
||||
"die Vergangenheit oder für heute eingetragen werden."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:82
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:97
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your cache rating was ignored, because %s does not have a rating "
|
||||
@ -86,11 +106,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Deine Cachewertung wurde jedoch ignoriert, weil %s kein Bewertungssystem hat."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:92
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:108
|
||||
msgid "Recommending is allowed only for 'Found it' logtypes."
|
||||
msgstr "Empfehlungen sind nur bei 'Gefunden'-Logs erlaubt."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:101
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:118
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
||||
@ -99,15 +119,7 @@ msgstr ""
|
||||
"Deine Angabe \"benötigt Wartung\" wurde jedoch ignoriert, weil es diese "
|
||||
"Funktion bei %s nicht gibt."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:124
|
||||
msgid ""
|
||||
"This cache is archived. Only admins and the owner are allowed to add a log "
|
||||
"entry."
|
||||
msgstr ""
|
||||
"Dieser Cache ist archiviert. Nur OC-Admins und der Besitzer können "
|
||||
"Logeinträge machen."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:128
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:136
|
||||
msgid ""
|
||||
"This cache is an Event cache. You cannot \"Find it\"! (But - you may "
|
||||
"\"Comment\" on it.)"
|
||||
@ -115,26 +127,26 @@ msgstr ""
|
||||
"Dies ist ein Event-Cache. Du kannst ihn nicht \"finden\" (aber du kannst "
|
||||
"einen Hinweis loggen)."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:130
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:138
|
||||
msgid "Your have to supply some text for your comment."
|
||||
msgstr "Du musst einen Text für dein Hinweislog eingeben!"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:143
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:151
|
||||
msgid "This cache requires a password. You didn't provide one!"
|
||||
msgstr ""
|
||||
"Dieser Cache kann nur mit Kennwort geloggt werden, aber du hast keines "
|
||||
"angegeben."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:145
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:153
|
||||
msgid "Invalid password!"
|
||||
msgstr "Ungültiges Kennwort!"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:194
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:203
|
||||
msgid "You have already submitted a log entry with exactly the same contents."
|
||||
msgstr ""
|
||||
"Du hast bereits einen Logeintrag mit genau dem gleichen Inhalt gemacht."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:213
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:222
|
||||
msgid ""
|
||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||
"\"Comments\" only!"
|
||||
@ -142,49 +154,49 @@ msgstr ""
|
||||
"Du hast diesen Cache bereits als gefunden geloggt. Ein zweites Fundlog ist "
|
||||
"nicht möglich, aber du kannst stattdessen einen Hinweis loggen."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:215
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:224
|
||||
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||
msgstr ""
|
||||
"Als Besitzer des Caches kannst du nur Hinweise loggen, keine Funde oder "
|
||||
"Nichtfunde."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:233
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:242
|
||||
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||
msgstr ""
|
||||
"Du hast diesen Cache bereits bewertet. Deine Bewertung ist nicht änderbar."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:250
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:259
|
||||
msgid "You have already recommended this cache once."
|
||||
msgstr "Du hast diesen Cache bereits empfohlen."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:257
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:266
|
||||
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||
msgstr ""
|
||||
"Du musst mehr Caches finden, um eine weitere Bewertung abgeben zu können!"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/services/logs/submit.php:409
|
||||
#: c:\source\oc\okapi\following2/okapi/services/logs/submit.php:430
|
||||
msgid "Your cache log entry was posted successfully."
|
||||
msgstr "Dein Log wurde veröffentlicht."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:5
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorize.tpl.php:5
|
||||
msgid "Authorization Form"
|
||||
msgstr "Authorisierungs-Formular"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:46
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorize.tpl.php:46
|
||||
msgid "Expired request"
|
||||
msgstr "Anfrage abgelaufen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:47
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorize.tpl.php:47
|
||||
msgid "Unfortunately, the request has expired. Please try again."
|
||||
msgstr ""
|
||||
"Die Anfrage ist wegen Zeitüberschreitung abgelaufen. Bitte versuche es noch "
|
||||
"einmal."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:49
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorize.tpl.php:49
|
||||
msgid "External application is requesting access..."
|
||||
msgstr "Eine externe Anwendung wünscht Zugriff ..."
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:50
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorize.tpl.php:50
|
||||
#, php-format
|
||||
msgid ""
|
||||
"<b>%s</b> wants to access your <b>%s</b> account. Do you agree to grant "
|
||||
@ -193,15 +205,15 @@ msgstr ""
|
||||
"<b>%s</b> möchte auf dein <b>%s</b>-Benutzerkonto zugreifen. Möchtest du "
|
||||
"dieser Anwendung Zugriff gewähren?"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:53
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorize.tpl.php:53
|
||||
msgid "I agree"
|
||||
msgstr "Ja"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:54
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorize.tpl.php:54
|
||||
msgid "Decline"
|
||||
msgstr "Nein"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorize.tpl.php:56
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorize.tpl.php:56
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -229,15 +241,15 @@ msgstr ""
|
||||
"\t\t\t\t\tDu kannst diese Erlaubnis jederzeit widerrufen.</p>\n"
|
||||
"\t\t\t\t"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorized.tpl.php:5
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorized.tpl.php:5
|
||||
msgid "Authorization Succeeded"
|
||||
msgstr "Authorisierung erfolgreich"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorized.tpl.php:28
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorized.tpl.php:28
|
||||
msgid "Access successfully granted"
|
||||
msgstr "Zugang wurde gewährt"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/authorized.tpl.php:29
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/authorized.tpl.php:29
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -254,15 +266,15 @@ msgstr ""
|
||||
"PIN-Code ein:</p>\n"
|
||||
"\t\t\t"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:5
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/index.tpl.php:5
|
||||
msgid "My Apps"
|
||||
msgstr "Meine Apps"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:29
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/index.tpl.php:29
|
||||
msgid "Your external applications"
|
||||
msgstr "Deine externe Anwendung"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:31
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/index.tpl.php:31
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -284,11 +296,11 @@ msgstr ""
|
||||
"Aktionen mehr unter deinem \t\t\t\t\tBenutzername ausführen können.</p>\n"
|
||||
"\t\t\t\t"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:45
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/index.tpl.php:45
|
||||
msgid "remove"
|
||||
msgstr "entfernen"
|
||||
|
||||
#: c:\source\oc\server-3.0\htdocs\okapi/views/apps/index.tpl.php:50
|
||||
#: c:\source\oc\okapi\following2/okapi/views/apps/index.tpl.php:50
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -308,3 +320,10 @@ msgstr ""
|
||||
"\t\t\t\t\tdazu ermächtigt. Sobald du externe Opencaching-Anwendungen "
|
||||
"aktivierst, werden diese hier erscheinen.</p>\n"
|
||||
"\t\t\t\t"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "This cache is archived. Only admins and the owner are allowed to add a "
|
||||
#~ "log entry."
|
||||
#~ msgstr ""
|
||||
#~ "Dieser Cache ist archiviert. Nur OC-Admins und der Besitzer können "
|
||||
#~ "Logeinträge machen."
|
||||
|
BIN
htdocs/okapi/locale/it_IT/LC_MESSAGES/okapi_messages.mo
Normal file
BIN
htdocs/okapi/locale/it_IT/LC_MESSAGES/okapi_messages.mo
Normal file
Binary file not shown.
314
htdocs/okapi/locale/it_IT/LC_MESSAGES/okapi_messages.po
Normal file
314
htdocs/okapi/locale/it_IT/LC_MESSAGES/okapi_messages.po
Normal file
@ -0,0 +1,314 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OKAPI\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-03-26 16:20+0100\n"
|
||||
"PO-Revision-Date: 2013-03-30 15:55+0100\n"
|
||||
"Last-Translator: Stefano Cotterli <stefanocotterli@gmail.com>\n"
|
||||
"Language-Team: following <following@online.de>\n"
|
||||
"Language: Italian\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
|
||||
"X-Poedit-Basepath: c:\\source\\okapi\\following2\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"X-Generator: Poedit 1.5.5\n"
|
||||
"X-Poedit-SearchPath-0: c:\\source\\okapi\\following2\n"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/geocaches.php:777
|
||||
msgid "Stage"
|
||||
msgstr "Passo"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/geocaches.php:897
|
||||
#, php-format
|
||||
msgid ""
|
||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||
"a> site."
|
||||
msgstr ""
|
||||
"La deescrizione di questa <a href='%s'>geocache</a>proviene dal sito <a "
|
||||
"href='%s'>%s</a>."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:31
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:48
|
||||
msgid "hidden by"
|
||||
msgstr "nascosta da"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:50
|
||||
#, php-format
|
||||
msgid "%d recommendation"
|
||||
msgid_plural "%d recommendations"
|
||||
msgstr[0] "%d raccomandazione"
|
||||
msgstr[1] "%d raccomandazioni"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:51
|
||||
#, php-format
|
||||
msgid "found %d time"
|
||||
msgid_plural "found %d times"
|
||||
msgstr[0] "trovata %d volta"
|
||||
msgstr[1] "trovata %d volte"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:54
|
||||
#, php-format
|
||||
msgid "%d trackable"
|
||||
msgid_plural "%d trackables"
|
||||
msgstr[0] "%d travel bug"
|
||||
msgstr[1] "%d travel bugs"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:58
|
||||
msgid "Personal notes"
|
||||
msgstr "Note personali"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:62
|
||||
msgid "Attributes"
|
||||
msgstr "Attributi"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:66
|
||||
msgid "Trackables"
|
||||
msgstr "Travel bugs"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:84
|
||||
msgid "Images"
|
||||
msgstr "Immagini"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:91
|
||||
msgid "Spoilers"
|
||||
msgstr "Spoiler"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/caches/formatters/gpxfile.tpl.php:99
|
||||
msgid "Image descriptions"
|
||||
msgstr "Descrizione immagine"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:62
|
||||
msgid ""
|
||||
"You are trying to publish a log entry with a date in future. Cache log "
|
||||
"entries are allowed to be published in the past, but NOT in the future."
|
||||
msgstr ""
|
||||
"Hai cercato di pubblicare un log con una data nel futuro. E' permsso loggare "
|
||||
"una cache con una data passata, ma NON futura."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:82
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your cache rating was ignored, because %s does not have a rating "
|
||||
"system."
|
||||
msgstr ""
|
||||
"Tuttavia, la tua valutazione della cache sarà ignorata, perché %s non ha un "
|
||||
"sistema di valutazione."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:92
|
||||
msgid "Recommending is allowed only for 'Found it' logtypes."
|
||||
msgstr "Le raccomandazioni sono ammesse solo per i log di tipo 'Trovata'"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:101
|
||||
#, php-format
|
||||
msgid ""
|
||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
||||
"support this feature."
|
||||
msgstr ""
|
||||
"Tuttavia, la tua segnalazione di \"manutenzione necessaria\" sarà ignorata, "
|
||||
"perché %s non supporta questa opzione."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:119
|
||||
msgid ""
|
||||
"This cache is an Event cache. You cannot \"Find it\"! (But - you may "
|
||||
"\"Comment\" on it.)"
|
||||
msgstr ""
|
||||
"Questa cache è una cache Evento. Non puoi \"Trovarla\"! (Ma puoi inserirci "
|
||||
"un \"Commento\")."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:121
|
||||
msgid "Your have to supply some text for your comment."
|
||||
msgstr "Devi inserire del testo per il tuo commento."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:134
|
||||
msgid "This cache requires a password. You didn't provide one!"
|
||||
msgstr "Questa cache richiede una password, ma non ne hai fornita nessuuna."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:136
|
||||
msgid "Invalid password!"
|
||||
msgstr "Password non valida!"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:186
|
||||
msgid "You have already submitted a log entry with exactly the same contents."
|
||||
msgstr "Hai già inserito un log esattamente con lo stesso contenuto."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:205
|
||||
msgid ""
|
||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||
"\"Comments\" only!"
|
||||
msgstr ""
|
||||
"Hai già inserito un log \"Trovata\". Adesso puoi inserire solamente "
|
||||
"\"Commenti\"!"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:207
|
||||
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||
msgstr "Sei il proprietario della cache. Puoi inserire solamente \"Commenti\"!"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:225
|
||||
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||
msgstr ""
|
||||
"Hai giàvalutato questa cache. La tua valutazione non può essere cambiata."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:242
|
||||
msgid "You have already recommended this cache once."
|
||||
msgstr "Hai già raccmandato questa cache."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:249
|
||||
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||
msgstr ""
|
||||
"Non hai possibilità di dare raccomandazioni. Prima devio trovare altre cache!"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/services/logs/submit.php:413
|
||||
msgid "Your cache log entry was posted successfully."
|
||||
msgstr "Il tuo log sulla cache è stato correttamente inserito."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorize.tpl.php:5
|
||||
msgid "Authorization Form"
|
||||
msgstr "Modulo di autorizzazione"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorize.tpl.php:46
|
||||
msgid "Expired request"
|
||||
msgstr "Richiesta scaduta"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorize.tpl.php:47
|
||||
msgid "Unfortunately, the request has expired. Please try again."
|
||||
msgstr "Sfortunatamente, la richiesta è scaduta. Per favore riprova."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorize.tpl.php:49
|
||||
msgid "External application is requesting access..."
|
||||
msgstr "Una applicazione esterna sta richiedendo l'accesso."
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorize.tpl.php:50
|
||||
#, php-format
|
||||
msgid ""
|
||||
"<b>%s</b> wants to access your <b>%s</b> account. Do you agree to grant "
|
||||
"access to this application?"
|
||||
msgstr ""
|
||||
"<b>%s</b> vuole accedere al tuo account <b>%s</b>. Sei d'accordo nel "
|
||||
"concedere l'accesso a questa applicazione?"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorize.tpl.php:53
|
||||
msgid "I agree"
|
||||
msgstr "Sono d'accordo"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorize.tpl.php:54
|
||||
msgid "Decline"
|
||||
msgstr "No"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorize.tpl.php:56
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
||||
"OKAPI Framework</a>.\n"
|
||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
||||
"methods delivered\n"
|
||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
||||
"name.\n"
|
||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
||||
"\t\t\t\t"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Una volta concessa, l'autorizzazoine è valida finché non venga\n"
|
||||
"\t\t\t\t\trevocata nella pagina di <a href='%s'>gestione applicazioni</a>.</"
|
||||
"p>\n"
|
||||
"\t\t\t\t\t<p>L'applicazione accederà al tuo account tramite il <a "
|
||||
"href='%s'>frameword OKAPI</a>.\n"
|
||||
"\t\t\t\t\tSe permetti questa richiesta, l'applicazione potrà accedere a "
|
||||
"tutti i metodi forniti\n"
|
||||
"\t\t\t\t\tdal framework OKAPI, per es. postare i log delle geocache a tuo "
|
||||
"nome..\n"
|
||||
"\t\t\t\t\tPuoi revocare questo permesso in qualsiasi momento.</p>\n"
|
||||
"\t\t\t\t"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorized.tpl.php:5
|
||||
msgid "Authorization Succeeded"
|
||||
msgstr "Autorizzazione concessa"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorized.tpl.php:28
|
||||
msgid "Access successfully granted"
|
||||
msgstr "Accesso correttamente consentito"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/authorized.tpl.php:29
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
||||
"b>\n"
|
||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
||||
"code:</p>\n"
|
||||
"\t\t\t"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>Hai appena concesso all'applicazione \"%s\" l'accesso al tuo "
|
||||
"account %s.</b>\n"
|
||||
"\t\t\t\tPer completare l'operazione, riorna a %s e inserisci il seguente "
|
||||
"codice PIN:</p>\n"
|
||||
"\t\t\t"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/index.tpl.php:5
|
||||
msgid "My Apps"
|
||||
msgstr "Mie App"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/index.tpl.php:29
|
||||
msgid "Your external applications"
|
||||
msgstr "Le tue applicazioni esterne"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/index.tpl.php:31
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
||||
"your <b>%s</b> account.\n"
|
||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
||||
"privileges.\n"
|
||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
||||
"to perform any\n"
|
||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
||||
"\t\t\t\t"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Questa è la lista delle applicazioni a cui hai concesso "
|
||||
"l'accesso al tuo account <b>%s</b.\n"
|
||||
"\t\t\t\t\tQuesta pagina ti da la possibilità di revocare tutti privilegi "
|
||||
"precedentemente concessi.\n"
|
||||
"\t\t\t\t\tQundo clicchi su \"rimuovi\" all'applicazione non sarà più "
|
||||
"concesso eseguire nessuna\n"
|
||||
" \t\t\t\t\tazione per tuo conto.</p>\n"
|
||||
"\t\t\t\t"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/index.tpl.php:45
|
||||
msgid "remove"
|
||||
msgstr "entfernen"
|
||||
|
||||
#: c:\source\okapi\following2/okapi/views/apps/index.tpl.php:50
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
||||
"external applications\n"
|
||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
||||
"authorized to act\n"
|
||||
"\t\t\t\t\ton your behalf. Once you start using external OpenCaching "
|
||||
"applications, they will appear here.</p>\n"
|
||||
"\t\t\t\t"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Grazie al <a href='%s'>framework OKAPI</a>puoi concedere ad "
|
||||
"applicazioni esterne\n"
|
||||
"\t\t\t\t\t l'accesso al tuo account <b>%s</b>. Attualmente non ci son "
|
||||
"applicazioni autorizzate\n"
|
||||
"\t\t\t\t\tad agire per tuo conto. Quando userai applicazioni esterne a "
|
||||
"OpenCaching, queste appariranno qui</p>\n"
|
||||
"\t\t\t\t"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "This cache is archived. Only admins and the owner are allowed to add a "
|
||||
#~ "log entry."
|
||||
#~ msgstr ""
|
||||
#~ "Dieser Cache ist archiviert. Nur OC-Admins und der Besitzer können "
|
||||
#~ "Logeinträge machen."
|
@ -9,8 +9,9 @@ class Locales
|
||||
'en' => array('lang' => 'en', 'locale' => 'en_US.utf8', 'name' => 'English'),
|
||||
'nl' => array('lang' => 'nl', 'locale' => 'nl_NL.utf8', 'name' => 'Dutch'),
|
||||
'de' => array('lang' => 'de', 'locale' => 'de_DE.utf8', 'name' => 'German'),
|
||||
'it' => array('lang' => 'it', 'locale' => 'it_IT.utf8', 'name' => 'Italian'),
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of locales that should be installed on the system in order
|
||||
* for all translations to work properly.
|
||||
@ -22,7 +23,7 @@ class Locales
|
||||
$arr[] = $value['locale'];
|
||||
return $arr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of locales installed on the current system.
|
||||
*/
|
||||
@ -34,14 +35,14 @@ class Locales
|
||||
$arr[] = $item;
|
||||
return $arr;
|
||||
}
|
||||
|
||||
|
||||
private static function get_locale_for_language($lang)
|
||||
{
|
||||
if (isset(self::$languages[$lang]))
|
||||
return self::$languages[$lang]['locale'];
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static function get_best_locale($langprefs)
|
||||
{
|
||||
foreach ($langprefs as $lang)
|
||||
|
Binary file not shown.
@ -2,31 +2,40 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OKAPI\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-08-23 10:20+0100\n"
|
||||
"PO-Revision-Date: 2012-08-23 10:27+0100\n"
|
||||
"POT-Creation-Date: 2013-02-19 10:36+0100\n"
|
||||
"PO-Revision-Date: 2013-02-19 10:37+0100\n"
|
||||
"Last-Translator: Wojciech Rygielski <rygielski@mimuw.edu.pl>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: pl_PL\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
|
||||
"X-Poedit-Basepath: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api\\okapi\n"
|
||||
"Plural-Forms: nplurals=3; plural= n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Poedit-Language: Polish\n"
|
||||
"X-Poedit-Country: POLAND\n"
|
||||
"X-Poedit-Basepath: D:\\PRIV\\Projekty\\EclipseWorkspace\\opencaching-api"
|
||||
"\\okapi\n"
|
||||
"Plural-Forms: nplurals=3; plural= n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2;\n"
|
||||
"X-Poedit-SourceCharset: utf-8\n"
|
||||
"X-Generator: Poedit 1.5.5\n"
|
||||
"X-Poedit-SearchPath-0: .\n"
|
||||
|
||||
#: services/caches/geocaches.php:642
|
||||
#: services/caches/geocaches.php:746
|
||||
msgid "Stage"
|
||||
msgstr "Etap"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:27
|
||||
#: services/caches/formatters/gpxfile.tpl.php:44
|
||||
#: services/caches/geocaches.php:866
|
||||
#, php-format
|
||||
msgid ""
|
||||
"This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</"
|
||||
"a> site."
|
||||
msgstr "Opis <a href='%s'>skrzynki</a> pochodzi z serwisu <a href='%s'>%s</a>."
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:31
|
||||
#: services/caches/formatters/gpxfile.tpl.php:48
|
||||
msgid "hidden by"
|
||||
msgstr "ukryta przez"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:46
|
||||
#: services/caches/formatters/gpxfile.tpl.php:50
|
||||
#, php-format
|
||||
msgid "%d recommendation"
|
||||
msgid_plural "%d recommendations"
|
||||
@ -34,7 +43,7 @@ msgstr[0] "%d rekomendacja"
|
||||
msgstr[1] "%d rekomendacje"
|
||||
msgstr[2] "%d rekomendacji"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:47
|
||||
#: services/caches/formatters/gpxfile.tpl.php:51
|
||||
#, php-format
|
||||
msgid "found %d time"
|
||||
msgid_plural "found %d times"
|
||||
@ -42,7 +51,7 @@ msgstr[0] "znaleziona %d raz"
|
||||
msgstr[1] "znaleziona %d razy"
|
||||
msgstr[2] "znaleziona %d razy"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:50
|
||||
#: services/caches/formatters/gpxfile.tpl.php:54
|
||||
#, php-format
|
||||
msgid "%d trackable"
|
||||
msgid_plural "%d trackables"
|
||||
@ -50,38 +59,46 @@ msgstr[0] "%d GeoKret (lub TravelBug)"
|
||||
msgstr[1] "%d GeoKrety (lub TravelBugi)"
|
||||
msgstr[2] "%d GeoKretów (lub TravelBugów)"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:54
|
||||
#: services/caches/formatters/gpxfile.tpl.php:58
|
||||
msgid "Personal notes"
|
||||
msgstr "Osobiste notatki"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:58
|
||||
#: services/caches/formatters/gpxfile.tpl.php:62
|
||||
msgid "Attributes"
|
||||
msgstr "Atrybuty"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:62
|
||||
#: services/caches/formatters/gpxfile.tpl.php:66
|
||||
msgid "Trackables"
|
||||
msgstr "Geokrety, Travelbugi itp."
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:80
|
||||
#: services/caches/formatters/gpxfile.tpl.php:84
|
||||
msgid "Images"
|
||||
msgstr "Obrazki"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:87
|
||||
#: services/caches/formatters/gpxfile.tpl.php:91
|
||||
msgid "Spoilers"
|
||||
msgstr "Spoilery"
|
||||
|
||||
#: services/caches/formatters/gpxfile.tpl.php:95
|
||||
#: services/caches/formatters/gpxfile.tpl.php:99
|
||||
msgid "Image descriptions"
|
||||
msgstr "Opisy obrazków"
|
||||
|
||||
#: services/logs/submit.php:62
|
||||
msgid "You are trying to publish a log entry with a date in future. Cache log entries are allowed to be published in the past, but NOT in the future."
|
||||
msgstr "Próbujesz opublikować wpis do logbooka używając daty w przyszłości. Wpisy mogą być publikowane z datą w przeszłości, ale NIE w przyszłości."
|
||||
msgid ""
|
||||
"You are trying to publish a log entry with a date in future. Cache log "
|
||||
"entries are allowed to be published in the past, but NOT in the future."
|
||||
msgstr ""
|
||||
"Próbujesz opublikować wpis do logbooka używając daty w przyszłości. Wpisy "
|
||||
"mogą być publikowane z datą w przeszłości, ale NIE w przyszłości."
|
||||
|
||||
#: services/logs/submit.php:82
|
||||
#, php-format
|
||||
msgid "However, your cache rating was ignored, because %s does not have a rating system."
|
||||
msgstr "Niestety Twoja ocena skrzynki nie została zapisana, ponieważ %s nie prowadzi oceny skrzynek."
|
||||
msgid ""
|
||||
"However, your cache rating was ignored, because %s does not have a rating "
|
||||
"system."
|
||||
msgstr ""
|
||||
"Niestety Twoja ocena skrzynki nie została zapisana, ponieważ %s nie prowadzi "
|
||||
"oceny skrzynek."
|
||||
|
||||
#: services/logs/submit.php:92
|
||||
msgid "Recommending is allowed only for 'Found it' logtypes."
|
||||
@ -89,54 +106,65 @@ msgstr "Rekomendacje są dozwolone jedynie z wpisem \"Znaleziona\"."
|
||||
|
||||
#: services/logs/submit.php:101
|
||||
#, php-format
|
||||
msgid "However, your \"needs maintenance\" flag was ignored, because %s does not support this feature."
|
||||
msgstr "Niestety, wpis \"potrzebny serwis\" został zignorowany, ponieważ %s nie wspiera tej funkcjonalności."
|
||||
msgid ""
|
||||
"However, your \"needs maintenance\" flag was ignored, because %s does not "
|
||||
"support this feature."
|
||||
msgstr ""
|
||||
"Niestety, wpis \"potrzebny serwis\" został zignorowany, ponieważ %s nie "
|
||||
"wspiera tej funkcjonalności."
|
||||
|
||||
#: services/logs/submit.php:124
|
||||
msgid "This cache is archived. Only admins and the owner are allowed to add a log entry."
|
||||
msgstr "Ta skrzynka jest zarchiwizowana. Jedynie administratorzy oraz właściciel mogą dodawać komentarze."
|
||||
#: services/logs/submit.php:119
|
||||
msgid ""
|
||||
"This cache is an Event cache. You cannot \"Find it\"! (But - you may "
|
||||
"\"Comment\" on it.)"
|
||||
msgstr ""
|
||||
"Ta skrzynka jest typu Wydarzenie. Nie możesz jej \"znaleźć\"! (Ale - możesz "
|
||||
"dodać wpis typu \"Komentarz\".)"
|
||||
|
||||
#: services/logs/submit.php:128
|
||||
msgid "This cache is an Event cache. You cannot \"Find it\"! (But - you may \"Comment\" on it.)"
|
||||
msgstr "Ta skrzynka jest typu Wydarzenie. Nie możesz jej \"znaleźć\"! (Ale - możesz dodać wpis typu \"Komentarz\".)"
|
||||
|
||||
#: services/logs/submit.php:130
|
||||
#: services/logs/submit.php:121
|
||||
msgid "Your have to supply some text for your comment."
|
||||
msgstr "Wpis typu \"Komentarz\" wymaga wpisania komentarza."
|
||||
|
||||
#: services/logs/submit.php:143
|
||||
#: services/logs/submit.php:134
|
||||
msgid "This cache requires a password. You didn't provide one!"
|
||||
msgstr "Ta skrzynka wymaga podania hasła. Nie wpisałeś go."
|
||||
|
||||
#: services/logs/submit.php:145
|
||||
#: services/logs/submit.php:136
|
||||
msgid "Invalid password!"
|
||||
msgstr "Niepoprawne hasło!"
|
||||
|
||||
#: services/logs/submit.php:194
|
||||
#: services/logs/submit.php:186
|
||||
msgid "You have already submitted a log entry with exactly the same contents."
|
||||
msgstr "Już opublikowałeś wcześniej wpis z dokładnie taką samą treścią."
|
||||
|
||||
#: services/logs/submit.php:213
|
||||
msgid "You have already submitted a \"Found it\" log entry once. Now you may submit \"Comments\" only!"
|
||||
msgstr "Już opublikowałeś jeden wpis typu \"Znaleziona\" dla tej skrzynki. Teraz możesz dodawać jedynie \"Komentarze\"!"
|
||||
#: services/logs/submit.php:205
|
||||
msgid ""
|
||||
"You have already submitted a \"Found it\" log entry once. Now you may submit "
|
||||
"\"Comments\" only!"
|
||||
msgstr ""
|
||||
"Już opublikowałeś jeden wpis typu \"Znaleziona\" dla tej skrzynki. Teraz "
|
||||
"możesz dodawać jedynie \"Komentarze\"!"
|
||||
|
||||
#: services/logs/submit.php:215
|
||||
#: services/logs/submit.php:207
|
||||
msgid "You are the owner of this cache. You may submit \"Comments\" only!"
|
||||
msgstr "Jesteś właścicielem tej skrzynki. Możesz przesyłać jedynie \"Komentarze\"."
|
||||
msgstr ""
|
||||
"Jesteś właścicielem tej skrzynki. Możesz przesyłać jedynie \"Komentarze\"."
|
||||
|
||||
#: services/logs/submit.php:233
|
||||
#: services/logs/submit.php:225
|
||||
msgid "You have already rated this cache once. Your rating cannot be changed."
|
||||
msgstr "Już oceniłeś tę skrzynkę. Ocena nie może być zmieniona."
|
||||
|
||||
#: services/logs/submit.php:250
|
||||
#: services/logs/submit.php:242
|
||||
msgid "You have already recommended this cache once."
|
||||
msgstr "Już raz zarekomendowałeś tę skrzynkę."
|
||||
|
||||
#: services/logs/submit.php:257
|
||||
#: services/logs/submit.php:249
|
||||
msgid "You don't have any recommendations to give. Find more caches first!"
|
||||
msgstr "Aktualnie nie możesz wystawić kolejnej rekomendacji. Znajdź najpierw więcej skrzynek!"
|
||||
msgstr ""
|
||||
"Aktualnie nie możesz wystawić kolejnej rekomendacji. Znajdź najpierw więcej "
|
||||
"skrzynek!"
|
||||
|
||||
#: services/logs/submit.php:409
|
||||
#: services/logs/submit.php:413
|
||||
msgid "Your cache log entry was posted successfully."
|
||||
msgstr "Twój wpis do logbooka został opublikowany pomyślnie."
|
||||
|
||||
@ -158,8 +186,12 @@ msgstr "Aplikacja zewnętrzna prosi o dostęp..."
|
||||
|
||||
#: views/apps/authorize.tpl.php:50
|
||||
#, php-format
|
||||
msgid "<b>%s</b> wants to access your <b>%s</b> account. Do you agree to grant access to this application?"
|
||||
msgstr "<b>%s</b> chce uzyskać dostęp do Twojego konta <b>%s</b>. Czy zgadzasz się na udzielenie dostępu tej aplikacji?"
|
||||
msgid ""
|
||||
"<b>%s</b> wants to access your <b>%s</b> account. Do you agree to grant "
|
||||
"access to this application?"
|
||||
msgstr ""
|
||||
"<b>%s</b> chce uzyskać dostęp do Twojego konta <b>%s</b>. Czy zgadzasz się "
|
||||
"na udzielenie dostępu tej aplikacji?"
|
||||
|
||||
#: views/apps/authorize.tpl.php:53
|
||||
msgid "I agree"
|
||||
@ -175,14 +207,23 @@ msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Once permission is granted it is valid until its withdrawal on\n"
|
||||
"\t\t\t\t\tthe <a href='%s'>applications management</a> page.</p>\n"
|
||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the OKAPI Framework</a>.\n"
|
||||
"\t\t\t\t\tIf you allow this request application will be able to access all methods delivered\n"
|
||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your name.\n"
|
||||
"\t\t\t\t\t<p>The application will access your acount via <a href='%s'>the "
|
||||
"OKAPI Framework</a>.\n"
|
||||
"\t\t\t\t\tIf you allow this request application will be able to access all "
|
||||
"methods delivered\n"
|
||||
"\t\t\t\t\tby the OKAPI Framework, i.e. post log entries on geocaches in your "
|
||||
"name.\n"
|
||||
"\t\t\t\t\tYou can revoke this permission at any moment.</p>\n"
|
||||
"\t\t\t\t"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p>Raz udzielona zgoda jest ważna aż do momentu jej wycofania na stronie <a href='%s'>zarządzania aplikacjami</a>.</p><p>Aplikacja będzie łączyć się z Twoim kontem poprzez <a href='%s'>platformę OKAPI</a> (strona w języku angielskim). Uzyskanie zgody na dostęp pozwoli aplikacji na korzystanie ze wszystkich metod udostępnianych przez platformę OKAPI (m.in. aplikacja będzie mogła umieszczać komentarze pod znajdowanymi przez Ciebie skrzynkami). Zgodę możesz wycofać w każdym momencie.</p>"
|
||||
"<p>Raz udzielona zgoda jest ważna aż do momentu jej wycofania na stronie <a "
|
||||
"href='%s'>zarządzania aplikacjami</a>.</p><p>Aplikacja będzie łączyć się z "
|
||||
"Twoim kontem poprzez <a href='%s'>platformę OKAPI</a> (strona w języku "
|
||||
"angielskim). Uzyskanie zgody na dostęp pozwoli aplikacji na korzystanie ze "
|
||||
"wszystkich metod udostępnianych przez platformę OKAPI (m.in. aplikacja "
|
||||
"będzie mogła umieszczać komentarze pod znajdowanymi przez Ciebie "
|
||||
"skrzynkami). Zgodę możesz wycofać w każdym momencie.</p>"
|
||||
|
||||
#: views/apps/authorized.tpl.php:5
|
||||
msgid "Authorization Succeeded"
|
||||
@ -196,13 +237,16 @@ msgstr "Pomyślnie dałeś dostęp"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</b>\n"
|
||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN code:</p>\n"
|
||||
"\t\t\t\t<p><b>You've just granted %s application access to your %s account.</"
|
||||
"b>\n"
|
||||
"\t\t\t\tTo complete the operation, go back to %s and enter the following PIN "
|
||||
"code:</p>\n"
|
||||
"\t\t\t"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p><b>Właśnie dałeś dostęp aplikacji %s do Twojego konta %s.</b>\n"
|
||||
"Aby zakończyć operację, wróć teraz do aplikacji %s i wpisz następujący kod PIN:</p>"
|
||||
"Aby zakończyć operację, wróć teraz do aplikacji %s i wpisz następujący kod "
|
||||
"PIN:</p>"
|
||||
|
||||
#: views/apps/index.tpl.php:5
|
||||
msgid "My Apps"
|
||||
@ -216,16 +260,21 @@ msgstr "Twoje zewnętrzne aplikacje"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to your <b>%s</b> account.\n"
|
||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted privileges.\n"
|
||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able to perform any\n"
|
||||
"\t\t\t\t\t<p>This is the list of applications which you granted access to "
|
||||
"your <b>%s</b> account.\n"
|
||||
"\t\t\t\t\tThis page gives you the abbility to revoke all previously granted "
|
||||
"privileges.\n"
|
||||
"\t\t\t\t\tOnce you click \"remove\" the application will no longer be able "
|
||||
"to perform any\n"
|
||||
"\t\t\t\t\tactions on your behalf.</p>\n"
|
||||
"\t\t\t\t"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p>Następującym aplikacjom zezwoliłeś na dostęp do swojego konta <b>%s</b>.\n"
|
||||
"Na tej stronie możesz wycofać udzielone poprzednio zezwolenia. Po kliknięciu\n"
|
||||
"\"usuń\" aplikacja nie będzie już mogła wykonywać żadnych operacji w Twoim imieniu.</p>"
|
||||
"Na tej stronie możesz wycofać udzielone poprzednio zezwolenia. Po "
|
||||
"kliknięciu\n"
|
||||
"\"usuń\" aplikacja nie będzie już mogła wykonywać żadnych operacji w Twoim "
|
||||
"imieniu.</p>"
|
||||
|
||||
#: views/apps/index.tpl.php:45
|
||||
msgid "remove"
|
||||
@ -235,18 +284,30 @@ msgstr "usuń"
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant external applications\n"
|
||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are authorized to act\n"
|
||||
"\t\t\t\t\ton your behalf. Once you start using external OpenCaching applications, they will appear here.</p>\n"
|
||||
"\t\t\t\t\t<p>Thanks to the <a href='%s'>OKAPI Framework</a> you can grant "
|
||||
"external applications\n"
|
||||
"\t\t\t\t\taccess to your <b>%s</b> account. Currently no applications are "
|
||||
"authorized to act\n"
|
||||
"\t\t\t\t\ton your behalf. Once you start using external OpenCaching "
|
||||
"applications, they will appear here.</p>\n"
|
||||
"\t\t\t\t"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"<p>Dzięki platformie <a href='%s'>OKAPI</a> możesz dawać zewnętrznym aplikacjom\n"
|
||||
"dostęp do Twojego konta <b>%s</b>. Aktualnie nie pozwalasz żadnej aplikacji na działania\n"
|
||||
"w Twoim imieniu. Jeśli kiedyś dodasz jakieś aplikacje, to ich lista pojawi się tutaj.</p>"
|
||||
"<p>Dzięki platformie <a href='%s'>OKAPI</a> możesz dawać zewnętrznym "
|
||||
"aplikacjom\n"
|
||||
"dostęp do Twojego konta <b>%s</b>. Aktualnie nie pozwalasz żadnej aplikacji "
|
||||
"na działania\n"
|
||||
"w Twoim imieniu. Jeśli kiedyś dodasz jakieś aplikacje, to ich lista pojawi "
|
||||
"się tutaj.</p>"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "This cache is archived. Only admins and the owner are allowed to add a "
|
||||
#~ "log entry."
|
||||
#~ msgstr ""
|
||||
#~ "Ta skrzynka jest zarchiwizowana. Jedynie administratorzy oraz właściciel "
|
||||
#~ "mogą dodawać komentarze."
|
||||
|
||||
#~ msgid "from among %d vote"
|
||||
|
||||
#~ msgid_plural "from among %d votes"
|
||||
#~ msgstr[0] "spośród %d oceny"
|
||||
#~ msgstr[1] "spośród %d ocen"
|
||||
|
@ -262,9 +262,9 @@ abstract class OAuthSignatureMethod {
|
||||
}
|
||||
|
||||
/**
|
||||
* The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
|
||||
* where the Signature Base String is the text and the key is the concatenated values (each first
|
||||
* encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
|
||||
* The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104]
|
||||
* where the Signature Base String is the text and the key is the concatenated values (each first
|
||||
* encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&'
|
||||
* character (ASCII code 38) even if empty.
|
||||
* - Chapter 9.2 ("HMAC-SHA1")
|
||||
*/
|
||||
@ -290,7 +290,7 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
|
||||
}
|
||||
|
||||
/**
|
||||
* The PLAINTEXT method does not provide any security protection and SHOULD only be used
|
||||
* The PLAINTEXT method does not provide any security protection and SHOULD only be used
|
||||
* over a secure channel such as HTTPS. It does not use the Signature Base String.
|
||||
* - Chapter 9.4 ("PLAINTEXT")
|
||||
*/
|
||||
@ -300,8 +300,8 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
|
||||
}
|
||||
|
||||
/**
|
||||
* oauth_signature is set to the concatenated encoded values of the Consumer Secret and
|
||||
* Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
|
||||
* oauth_signature is set to the concatenated encoded values of the Consumer Secret and
|
||||
* Token Secret, separated by a '&' character (ASCII code 38), even if either secret is
|
||||
* empty. The result MUST be encoded again.
|
||||
* - Chapter 9.4.1 ("Generating Signatures")
|
||||
*
|
||||
@ -323,10 +323,10 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
|
||||
}
|
||||
|
||||
/**
|
||||
* The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
|
||||
* [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
|
||||
* EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
|
||||
* verified way to the Service Provider, in a manner which is beyond the scope of this
|
||||
* The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in
|
||||
* [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for
|
||||
* EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a
|
||||
* verified way to the Service Provider, in a manner which is beyond the scope of this
|
||||
* specification.
|
||||
* - Chapter 9.3 ("RSA-SHA1")
|
||||
*/
|
||||
@ -727,7 +727,7 @@ class OAuthServer {
|
||||
protected function get_version(&$request) {
|
||||
$version = $request->get_parameter("oauth_version");
|
||||
if (!$version) {
|
||||
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
|
||||
// Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
|
||||
// Chapter 7.0 ("Accessing Protected Ressources")
|
||||
$version = '1.0';
|
||||
}
|
||||
@ -741,7 +741,7 @@ class OAuthServer {
|
||||
* figure out the signature with some defaults
|
||||
*/
|
||||
private function get_signature_method($request) {
|
||||
$signature_method = $request instanceof OAuthRequest
|
||||
$signature_method = $request instanceof OAuthRequest
|
||||
? $request->get_parameter("oauth_signature_method")
|
||||
: NULL;
|
||||
|
||||
@ -766,7 +766,7 @@ class OAuthServer {
|
||||
* try to find the consumer for the provided request's consumer key
|
||||
*/
|
||||
protected function get_consumer($request) {
|
||||
$consumer_key = $request instanceof OAuthRequest
|
||||
$consumer_key = $request instanceof OAuthRequest
|
||||
? $request->get_parameter("oauth_consumer_key")
|
||||
: NULL;
|
||||
|
||||
@ -838,7 +838,7 @@ class OAuthServer {
|
||||
private function check_timestamp($timestamp) {
|
||||
if( ! $timestamp )
|
||||
throw new OAuthMissingParameterException('oauth_timestamp');
|
||||
|
||||
|
||||
// verify that timestamp is recentish
|
||||
$now = time();
|
||||
if (abs($now - $timestamp) > $this->timestamp_threshold) {
|
||||
|
@ -23,6 +23,7 @@ class OkapiServiceRunner
|
||||
'services/apiref/method',
|
||||
'services/apiref/method_index',
|
||||
'services/apiref/issue',
|
||||
'services/attrs/info',
|
||||
'services/oauth/request_token',
|
||||
'services/oauth/authorize',
|
||||
'services/oauth/access_token',
|
||||
@ -53,13 +54,13 @@ class OkapiServiceRunner
|
||||
'services/replicate/fulldump',
|
||||
'services/replicate/info',
|
||||
);
|
||||
|
||||
|
||||
/** Check if method exists. */
|
||||
public static function exists($service_name)
|
||||
{
|
||||
return in_array($service_name, self::$all_names);
|
||||
}
|
||||
|
||||
|
||||
/** Get method options (is consumer required etc.). */
|
||||
public static function options($service_name)
|
||||
{
|
||||
@ -77,8 +78,8 @@ class OkapiServiceRunner
|
||||
$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Get method documentation file contents (stuff within the XML file).
|
||||
* If you're looking for a parsed representation, use services/apiref/method.
|
||||
*/
|
||||
@ -92,13 +93,13 @@ class OkapiServiceRunner
|
||||
throw new Exception("Missing documentation file: $service_name.xml");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Execute the method and return the result.
|
||||
*
|
||||
*
|
||||
* OKAPI methods return OkapiHttpResponses, but some MAY also return
|
||||
* PHP objects (see OkapiRequest::construct_inside_request for details).
|
||||
*
|
||||
*
|
||||
* If $request must be consistent with given method's options (must
|
||||
* include Consumer and Token, if they are required).
|
||||
*/
|
||||
@ -108,7 +109,7 @@ class OkapiServiceRunner
|
||||
|
||||
if (!self::exists($service_name))
|
||||
throw new Exception("Method does not exist: '$service_name'");
|
||||
|
||||
|
||||
$options = self::options($service_name);
|
||||
if ($options['min_auth_level'] >= 2 && $request->consumer == null)
|
||||
{
|
||||
@ -121,7 +122,7 @@ class OkapiServiceRunner
|
||||
throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ".
|
||||
"\$request->token MAY NOT be empty for Level 3 methods.");
|
||||
}
|
||||
|
||||
|
||||
$time_started = microtime(true);
|
||||
Okapi::gettext_domain_init();
|
||||
try
|
||||
@ -135,14 +136,14 @@ class OkapiServiceRunner
|
||||
throw $e;
|
||||
}
|
||||
$runtime = microtime(true) - $time_started;
|
||||
|
||||
|
||||
# Log the request to the stats table. Only valid requests (these which didn't end up
|
||||
# with an exception) are logged.
|
||||
self::save_stats($service_name, $request, $runtime);
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For internal use only. The stats table can be used to store any kind of
|
||||
* runtime-stats data, i.e. not only regarding services. This is a special
|
||||
@ -153,13 +154,13 @@ class OkapiServiceRunner
|
||||
{
|
||||
self::save_stats("extra/".$extra_name, $request, $runtime);
|
||||
}
|
||||
|
||||
|
||||
private static function save_stats($service_name, $request, $runtime)
|
||||
{
|
||||
# Getting rid of nulls. MySQL PRIMARY keys cannot contain nullable columns.
|
||||
# Temp table doesn't have primary key, but other stats tables (which are
|
||||
# dependant on stats table) - do.
|
||||
|
||||
|
||||
if ($request !== null) {
|
||||
$consumer_key = ($request->consumer != null) ? $request->consumer->key : 'anonymous';
|
||||
$user_id = (($request->token != null) && ($request->token instanceof OkapiAccessToken)) ? $request->token->user_id : -1;
|
||||
@ -172,7 +173,7 @@ class OkapiServiceRunner
|
||||
$user_id = -1;
|
||||
$calltype = 'internal';
|
||||
}
|
||||
|
||||
|
||||
Db::execute("
|
||||
insert into okapi_stats_temp (`datetime`, consumer_key, user_id, service_name, calltype, runtime)
|
||||
values (
|
||||
|
@ -21,7 +21,7 @@ class WebService
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$issue_id = $request->get_parameter('issue_id');
|
||||
@ -29,13 +29,13 @@ class WebService
|
||||
throw new ParamMissing('issue_id');
|
||||
if ((!preg_match("/^[0-9]+$/", $issue_id)) || (strlen($issue_id) > 6))
|
||||
throw new InvalidParam('issue_id');
|
||||
|
||||
|
||||
$cache_key = "apiref/issue#".$issue_id;
|
||||
$result = Cache::get($cache_key);
|
||||
if ($result == null)
|
||||
{
|
||||
# Download list of comments from Google Code Issue Tracker.
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
$opts = array(
|
||||
@ -54,7 +54,7 @@ class WebService
|
||||
"This is probably due to a temporary connection problem. Try again later or contact ".
|
||||
"us if this seems permanent.");
|
||||
}
|
||||
|
||||
|
||||
$doc = simplexml_load_string($xml);
|
||||
$result = array(
|
||||
'id' => $issue_id + 0,
|
||||
@ -63,11 +63,11 @@ class WebService
|
||||
'url' => (string)$doc->link[0]['href'],
|
||||
'comment_count' => $doc->entry->count()
|
||||
);
|
||||
|
||||
|
||||
# On one hand, we want newly added comments to show up quickly.
|
||||
# On the other, we don't want OKAPI to contantly query Google Code.
|
||||
# It's difficult to choose a correct timeout for this...
|
||||
|
||||
|
||||
Cache::set($cache_key, $result, 3600);
|
||||
}
|
||||
return Okapi::formatted_response($request, $result);
|
||||
|
@ -20,7 +20,7 @@ class WebService
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static function arg_desc($arg_node)
|
||||
{
|
||||
$attrs = $arg_node->attributes();
|
||||
@ -32,10 +32,10 @@ class WebService
|
||||
'description' =>
|
||||
(isset($attrs['default']) ? ("<p>Default value: <b>".$attrs['default']."</b></p>") : "").
|
||||
self::get_inner_xml($arg_node),
|
||||
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static function get_inner_xml($node)
|
||||
{
|
||||
$s = $node->asXML();
|
||||
@ -43,7 +43,7 @@ class WebService
|
||||
$length = strlen($s) - $start - (3 + strlen($node->getName()));
|
||||
return substr($s, $start, $length);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$methodname = $request->get_parameter('name');
|
||||
|
@ -21,7 +21,7 @@ class WebService
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$methodnames = OkapiServiceRunner::$all_names;
|
||||
|
@ -19,7 +19,7 @@ class WebService
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$result = array();
|
||||
|
@ -21,19 +21,19 @@ class WebService
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# The list of installations is periodically refreshed by contacting OKAPI
|
||||
# repository. This method usually displays the cached version of it.
|
||||
|
||||
|
||||
$cachekey = 'apisrv/installations';
|
||||
$backupkey = 'apisrv/installations-backup';
|
||||
$results = Cache::get($cachekey);
|
||||
if (!$results)
|
||||
{
|
||||
# Download the current list of OKAPI servers.
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
$opts = array(
|
||||
@ -49,17 +49,17 @@ class WebService
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
# Google failed on us. Try to respond with a backup list.
|
||||
|
||||
|
||||
$results = Cache::get($backupkey);
|
||||
if ($results)
|
||||
{
|
||||
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
|
||||
|
||||
# Backup has expired (or have never been cached). If we're on a development
|
||||
# server then probably it's okay. In production this SHOULD NOT happen.
|
||||
|
||||
|
||||
$results = array(
|
||||
array(
|
||||
'site_url' => Settings::get('SITE_URL'),
|
||||
@ -70,7 +70,7 @@ class WebService
|
||||
Cache::set($cachekey, $results, 12 * 3600); # so to retry no earlier than after 12 hours
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
|
||||
|
||||
$doc = simplexml_load_string($xml);
|
||||
$results = array();
|
||||
$i_was_included = false;
|
||||
@ -93,10 +93,10 @@ class WebService
|
||||
if ($site_url == Settings::get('SITE_URL'))
|
||||
$i_was_included = true;
|
||||
}
|
||||
|
||||
|
||||
# If running on a local development installation, then include the local
|
||||
# installation URL.
|
||||
|
||||
|
||||
if (!$i_was_included)
|
||||
{
|
||||
$results[] = array(
|
||||
@ -106,9 +106,9 @@ class WebService
|
||||
);
|
||||
# Contact OKAPI developers in order to get added to the official sites list!
|
||||
}
|
||||
|
||||
|
||||
# Cache it for one day. Also, save a backup (valid for 30 days).
|
||||
|
||||
|
||||
Cache::set($cachekey, $results, 86400);
|
||||
Cache::set($backupkey, $results, 86400*30);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ class WebService
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cachekey = "apisrv/stats";
|
||||
|
157
htdocs/okapi/services/attrs/attr_helper.inc.php
Normal file
157
htdocs/okapi/services/attrs/attr_helper.inc.php
Normal file
@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace okapi\services\attrs;
|
||||
|
||||
use Exception;
|
||||
use ErrorException;
|
||||
use okapi\Okapi;
|
||||
use okapi\Settings;
|
||||
use okapi\Cache;
|
||||
use okapi\OkapiRequest;
|
||||
use okapi\ParamMissing;
|
||||
use okapi\InvalidParam;
|
||||
use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use SimpleXMLElement;
|
||||
|
||||
|
||||
class AttrHelper
|
||||
{
|
||||
private static $CACHE_KEY = 'attrs/attrlist/1';
|
||||
private static $attr_dict = null;
|
||||
private static $last_refreshed = null;
|
||||
|
||||
/**
|
||||
* Forces the download of the new attributes from Google Code.
|
||||
*/
|
||||
private static function refresh_now()
|
||||
{
|
||||
try
|
||||
{
|
||||
$opts = array(
|
||||
'http' => array(
|
||||
'method' => "GET",
|
||||
'timeout' => 5.0
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($opts);
|
||||
$xml = file_get_contents("http://opencaching-api.googlecode.com/svn/trunk/etc/attributes.xml",
|
||||
false, $context);
|
||||
}
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
# Google failed on us. We won't update the cached attributes.
|
||||
return;
|
||||
}
|
||||
|
||||
$my_site_url = "http://opencaching.pl/"; // WRTODO
|
||||
$doc = simplexml_load_string($xml);
|
||||
$cachedvalue = array(
|
||||
'attr_dict' => array(),
|
||||
'last_refreshed' => time(),
|
||||
);
|
||||
foreach ($doc->attr as $attrnode)
|
||||
{
|
||||
$attr = array(
|
||||
'code' => (string)$attrnode['okapi_attr_id'],
|
||||
'gs_equiv' => null,
|
||||
'internal_id' => null,
|
||||
'names' => array(),
|
||||
'descriptions' => array()
|
||||
);
|
||||
foreach ($attrnode->groundspeak as $gsnode)
|
||||
{
|
||||
$attr['gs_equiv'] = array(
|
||||
'id' => (int)$gsnode['id'],
|
||||
'inc' => in_array((string)$gsnode['inc'], array("true", "1")) ? 1 : 0,
|
||||
'name' => (string)$gsnode['name']
|
||||
);
|
||||
}
|
||||
foreach ($attrnode->opencaching as $ocnode)
|
||||
{
|
||||
if ((string)$ocnode['site_url'] == $my_site_url) {
|
||||
$attr['internal_id'] = (int)$ocnode['id'];
|
||||
}
|
||||
}
|
||||
foreach ($attrnode->name as $namenode)
|
||||
{
|
||||
$attr['names'][(string)$namenode['lang']] = (string)$namenode;
|
||||
}
|
||||
foreach ($attrnode->desc as $descnode)
|
||||
{
|
||||
$xml = $descnode->asxml(); /* contains "<desc lang="...">" and "</desc>" */
|
||||
$innerxml = preg_replace("/(^[^>]+>)|(<[^<]+$)/us", "", $xml);
|
||||
$attr['descriptions'][(string)$descnode['lang']] = self::cleanup_string($innerxml);
|
||||
}
|
||||
$cachedvalue['attr_dict'][$attr['code']] = $attr;
|
||||
}
|
||||
|
||||
# Cache it for a month (just in case, usually it will be refreshed every day).
|
||||
|
||||
Cache::set(self::$CACHE_KEY, $cachedvalue, 30*86400);
|
||||
self::$attr_dict = $cachedvalue['attr_dict'];
|
||||
self::$last_refreshed = $cachedvalue['last_refreshed'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all the internal attributes (if not yet initialized). This
|
||||
* loads attribute values from the cache. If they are not present in the cache,
|
||||
* it won't download them from Google Code, it will initialize them as empty!
|
||||
*/
|
||||
private static function init_from_cache()
|
||||
{
|
||||
if (self::$attr_dict !== null)
|
||||
{
|
||||
/* Already initialized. */
|
||||
return;
|
||||
}
|
||||
$cachedvalue = Cache::get(self::$CACHE_KEY);
|
||||
if ($cachedvalue === null)
|
||||
{
|
||||
$cachedvalue = array(
|
||||
'attr_dict' => array(),
|
||||
'last_refreshed' => 0,
|
||||
);
|
||||
}
|
||||
self::$attr_dict = $cachedvalue['attr_dict'];
|
||||
self::$last_refreshed = $cachedvalue['last_refreshed'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cached attribute values might be stale. If they were not
|
||||
* refreshed in a while, perform the refresh from Google Code. (This might
|
||||
* take a couple of seconds, it should be done via a cronjob.)
|
||||
*/
|
||||
public static function refresh_if_stale()
|
||||
{
|
||||
self::init_from_cache();
|
||||
if (self::$last_refreshed < time() - 86400)
|
||||
self::refresh_now();
|
||||
if (self::$last_refreshed < time() - 3 * 86400)
|
||||
{
|
||||
Okapi::mail_admins(
|
||||
"OKAPI was unable to refresh attributes",
|
||||
"OKAPI periodically refreshes all cache attributes from the list\n".
|
||||
"kept in global repository. OKAPI tried to contact the repository,\n".
|
||||
"but it failed. Your list of attributes might be stale.\n\n".
|
||||
"You should probably update OKAPI or contact OKAPI developers."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a dictionary of all attributes. The format is the same as in the "attributes"
|
||||
* key returned by the "services/attrs/attrlist" method.
|
||||
*/
|
||||
public static function get_attrdict()
|
||||
{
|
||||
self::init_from_cache();
|
||||
return self::$attr_dict;
|
||||
}
|
||||
|
||||
/** "\n\t\tBla blabla\n\t\t<b>bla</b>bla.\n\t" => "Bla blabla <b>bla</b>bla." */
|
||||
private static function cleanup_string($s)
|
||||
{
|
||||
return preg_replace('/(^\s+)|(\s+$)/us', "", preg_replace('/\s+/us', " ", $s));
|
||||
}
|
||||
}
|
40
htdocs/okapi/services/attrs/info.php
Normal file
40
htdocs/okapi/services/attrs/info.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace okapi\services\attrs\info;
|
||||
|
||||
use Exception;
|
||||
use ErrorException;
|
||||
use okapi\Okapi;
|
||||
use okapi\Settings;
|
||||
use okapi\Cache;
|
||||
use okapi\OkapiRequest;
|
||||
use okapi\ParamMissing;
|
||||
use okapi\InvalidParam;
|
||||
use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use okapi\services\attrs\AttrHelper;
|
||||
|
||||
|
||||
class WebService
|
||||
{
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# The list of attributes is periodically refreshed by contacting OKAPI
|
||||
# repository (the refreshing is done via a cronjob). This method
|
||||
# displays the cached version of the list.
|
||||
|
||||
require_once 'attr_helper.inc.php';
|
||||
AttrHelper::refresh_if_stale();
|
||||
$results = array(
|
||||
'attributes' => AttrHelper::get_attrdict()
|
||||
);
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
12
htdocs/okapi/services/attrs/info.xml
Normal file
12
htdocs/okapi/services/attrs/info.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<xml>
|
||||
<brief>ALPHA: Get the list of all cache attributes</brief>
|
||||
<issue-id>194</issue-id>
|
||||
<desc>
|
||||
This method is in its ALPHA stage. It's signature will most probably
|
||||
change, or it might be removed altogether. You should not use it!
|
||||
</desc>
|
||||
<common-format-params/>
|
||||
<returns>
|
||||
Not yet documented. You should not use this method.
|
||||
</returns>
|
||||
</xml>
|
@ -22,47 +22,47 @@ class WebService
|
||||
{
|
||||
private static $shutdown_function_registered = false;
|
||||
private static $files_to_unlink = array();
|
||||
|
||||
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$cache_codes = $request->get_parameter('cache_codes');
|
||||
if ($cache_codes === null) throw new ParamMissing('cache_codes');
|
||||
|
||||
|
||||
# Issue 106 requires us to allow empty list of cache codes to be passed into this method.
|
||||
# All of the queries below have to be ready for $cache_codes to be empty!
|
||||
|
||||
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
$images = $request->get_parameter('images');
|
||||
if (!$images) $images = "all";
|
||||
if (!in_array($images, array("none", "all", "spoilers", "nonspoilers")))
|
||||
throw new InvalidParam('images');
|
||||
|
||||
|
||||
# Start creating ZIP archive.
|
||||
|
||||
|
||||
$tempfilename = Okapi::get_var_dir()."/garmin".time().rand(100000,999999).".zip";
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($tempfilename, ZIPARCHIVE::CREATE) !== true)
|
||||
throw new Exception("ZipArchive class could not create temp file $tempfilename. Check permissions!");
|
||||
|
||||
|
||||
# Create basic structure
|
||||
|
||||
|
||||
$zip->addEmptyDir("Garmin");
|
||||
$zip->addEmptyDir("Garmin/GPX");
|
||||
$zip->addEmptyDir("Garmin/GeocachePhotos");
|
||||
|
||||
|
||||
# Include a GPX file compatible with Garmin devices. It should include all
|
||||
# Geocaching.com (groundspeak:) and Opencaching.com (ox:) extensions. It will
|
||||
# also include image references (actual images will be added as separate files later)
|
||||
# and personal data (if the method was invoked using Level 3 Authentication).
|
||||
|
||||
|
||||
$zip->addFromString("Garmin/GPX/opencaching".time().rand(100000,999999).".gpx",
|
||||
OkapiServiceRunner::call('services/caches/formatters/gpx', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array(
|
||||
@ -81,7 +81,7 @@ class WebService
|
||||
)))->get_body());
|
||||
|
||||
# Then, include all the images.
|
||||
|
||||
|
||||
$caches = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('cache_codes' => $cache_codes,
|
||||
'langpref' => $langpref, 'fields' => "images")));
|
||||
@ -118,21 +118,21 @@ class WebService
|
||||
}
|
||||
if (!$tmp)
|
||||
continue; # unsupported file extension
|
||||
|
||||
|
||||
if ($img['is_spoiler']) {
|
||||
$zip->addEmptyDir($dir."/Spoilers");
|
||||
$zippath = $dir."/Spoilers/".$img['unique_caption'].".jpg";
|
||||
} else {
|
||||
$zippath = $dir."/".$img['unique_caption'].".jpg";
|
||||
}
|
||||
|
||||
|
||||
# The safest way would be to use the URL, but that would be painfully slow!
|
||||
# That's why we're trying to access files directly (and fail silently on error).
|
||||
# This was tested on OCPL server only.
|
||||
|
||||
|
||||
# Note: Oliver Dietz (oc.de) replied that images with 'local' set to 0 could not
|
||||
# be accessed locally. But all the files have 'local' set to 1 anyway.
|
||||
|
||||
|
||||
$syspath = Settings::get('IMAGES_DIR')."/".$img['uuid'].".jpg";
|
||||
if (file_exists($syspath))
|
||||
{
|
||||
@ -142,9 +142,9 @@ class WebService
|
||||
}
|
||||
else
|
||||
{
|
||||
# If file exists, but does not end with ".jpg", we will create
|
||||
# If file exists, but does not end with ".jpg", we will create
|
||||
# JPEG version of it and store it in the cache.
|
||||
|
||||
|
||||
$cache_key = "jpg#".$img['uuid'];
|
||||
$jpeg_contents = Cache::get($cache_key);
|
||||
if ($jpeg_contents === null)
|
||||
@ -167,7 +167,7 @@ class WebService
|
||||
# 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);
|
||||
@ -181,15 +181,15 @@ class WebService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$zip->close();
|
||||
|
||||
|
||||
# The result could be big. Bigger than our memory limit. We will
|
||||
# return an open file stream instead of a string. We also should
|
||||
# set a higher time limit, because downloading this response may
|
||||
# take some time over slow network connections (and I'm not sure
|
||||
# what is the PHP's default way of handling such scenario).
|
||||
|
||||
|
||||
set_time_limit(600);
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "application/zip";
|
||||
@ -200,14 +200,14 @@ class WebService
|
||||
self::add_file_to_unlink($tempfilename);
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
private static function add_file_to_unlink($filename)
|
||||
{
|
||||
if (!self::$shutdown_function_registered)
|
||||
register_shutdown_function(array("okapi\\services\\caches\\formatters\\garmin\\WebService", "unlink_temporary_files"));
|
||||
self::$files_to_unlink[] = $filename;
|
||||
}
|
||||
|
||||
|
||||
public static function unlink_temporary_files()
|
||||
{
|
||||
foreach (self::$files_to_unlink as $filename)
|
||||
|
@ -13,6 +13,7 @@ use okapi\OkapiAccessToken;
|
||||
use okapi\InvalidParam;
|
||||
use okapi\services\caches\search\SearchAssistant;
|
||||
use okapi\OkapiInternalConsumer;
|
||||
use okapi\Db;
|
||||
|
||||
class WebService
|
||||
{
|
||||
@ -35,7 +36,7 @@ class WebService
|
||||
'Own' => 'Unknown Cache',
|
||||
'Other' => 'Unknown Cache'
|
||||
);
|
||||
|
||||
|
||||
/** Maps OKAPI's 'size2' values to geocaching.com size codes. */
|
||||
public static $cache_GPX_sizes = array(
|
||||
'none' => 'Virtual',
|
||||
@ -47,20 +48,20 @@ class WebService
|
||||
'xlarge' => 'Large',
|
||||
'other' => 'Other',
|
||||
);
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$vars = array();
|
||||
|
||||
|
||||
# Validating arguments. We will also assign some of them to the
|
||||
# $vars variable which we will use later in the GPS template.
|
||||
|
||||
|
||||
$cache_codes = $request->get_parameter('cache_codes');
|
||||
if ($cache_codes === null) throw new ParamMissing('cache_codes');
|
||||
|
||||
# Issue 106 requires us to allow empty list of cache codes to be passed into this method.
|
||||
# All of the queries below have to be ready for $cache_codes to be empty!
|
||||
|
||||
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
foreach (array('ns_ground', 'ns_gsak', 'ns_ox', 'latest_logs', 'alt_wpts', 'mark_found') as $param)
|
||||
@ -73,7 +74,7 @@ class WebService
|
||||
}
|
||||
if ($vars['latest_logs'] && (!$vars['ns_ground']))
|
||||
throw new BadRequest("In order for 'latest_logs' to work you have to also include 'ns_ground' extensions.");
|
||||
|
||||
|
||||
$tmp = $request->get_parameter('my_notes');
|
||||
if (!$tmp) $tmp = "none";
|
||||
if (!in_array($tmp, array("none", "desc:text")))
|
||||
@ -81,39 +82,39 @@ class WebService
|
||||
if (($tmp != 'none') && ($request->token == null))
|
||||
throw new BadRequest("Level 3 Authentication is required to access my_notes data.");
|
||||
$vars['my_notes'] = $tmp;
|
||||
|
||||
|
||||
$images = $request->get_parameter('images');
|
||||
if (!$images) $images = 'descrefs:nonspoilers';
|
||||
if (!in_array($images, array('none', 'descrefs:nonspoilers', 'descrefs:all', 'ox:all')))
|
||||
throw new InvalidParam('images', "'$images'");
|
||||
$vars['images'] = $images;
|
||||
|
||||
|
||||
$tmp = $request->get_parameter('attrs');
|
||||
if (!$tmp) $tmp = 'desc:text';
|
||||
if (!in_array($tmp, array('none', 'desc:text', 'ox:tags')))
|
||||
throw new InvalidParam('attrs', "'$tmp'");
|
||||
$vars['attrs'] = $tmp;
|
||||
|
||||
|
||||
$tmp = $request->get_parameter('trackables');
|
||||
if (!$tmp) $tmp = 'none';
|
||||
if (!in_array($tmp, array('none', 'desc:list', 'desc:count')))
|
||||
throw new InvalidParam('trackables', "'$tmp'");
|
||||
$vars['trackables'] = $tmp;
|
||||
|
||||
|
||||
$tmp = $request->get_parameter('recommendations');
|
||||
if (!$tmp) $tmp = 'none';
|
||||
if (!in_array($tmp, array('none', 'desc:count')))
|
||||
throw new InvalidParam('recommendations', "'$tmp'");
|
||||
$vars['recommendations'] = $tmp;
|
||||
|
||||
|
||||
$lpc = $request->get_parameter('lpc');
|
||||
if ($lpc === null) $lpc = 10; # will be checked in services/caches/geocaches call
|
||||
|
||||
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
|
||||
|
||||
# We can get all the data we need from the services/caches/geocaches method.
|
||||
# We don't need to do any additional queries here.
|
||||
|
||||
|
||||
$fields = 'code|name|location|date_created|url|type|status|size|size2|oxsize'.
|
||||
'|difficulty|terrain|description|hint|rating|owner|url|internal_id';
|
||||
if ($vars['images'] != 'none')
|
||||
@ -134,15 +135,44 @@ class WebService
|
||||
$fields .= "|latest_logs";
|
||||
if ($vars['mark_found'])
|
||||
$fields .= "|is_found";
|
||||
|
||||
|
||||
$vars['caches'] = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('cache_codes' => $cache_codes,
|
||||
'langpref' => $langpref, 'fields' => $fields, 'lpc' => $lpc, 'user_uuid' => $user_uuid)));
|
||||
'langpref' => $langpref, 'fields' => $fields, 'lpc' => $lpc, 'user_uuid' => $user_uuid,
|
||||
'log_fields' => 'uuid|date|user|type|comment|internal_id|was_recommended')));
|
||||
$vars['installation'] = OkapiServiceRunner::call('services/apisrv/installation', new OkapiInternalRequest(
|
||||
new OkapiInternalConsumer(), null, array()));
|
||||
$vars['cache_GPX_types'] = self::$cache_GPX_types;
|
||||
$vars['cache_GPX_sizes'] = self::$cache_GPX_sizes;
|
||||
|
||||
|
||||
/* OC sites always used internal user_ids in their generated GPX files.
|
||||
* This might be considered an error in itself (groundspeak's XML namespace
|
||||
* doesn't allow that), but it very common (Garmin's OpenCaching.COM
|
||||
* also does that). Therefore, for backward-compatibility reasons, OKAPI
|
||||
* will do it the same way. See issue 174.
|
||||
*
|
||||
* Currently, the caches method does not expose "owner.internal_id" and
|
||||
* "latest_logs.user.internal_id" fields, we will read them manually
|
||||
* from the database here. */
|
||||
|
||||
$dict = array();
|
||||
foreach ($vars['caches'] as &$cache_ref)
|
||||
{
|
||||
$dict[$cache_ref['owner']['uuid']] = true;
|
||||
if (isset($cache_ref['latest_logs']))
|
||||
foreach ($cache_ref['latest_logs'] as &$log_ref)
|
||||
$dict[$log_ref['user']['uuid']] = true;
|
||||
}
|
||||
$rs = Db::query("
|
||||
select uuid, user_id
|
||||
from user
|
||||
where uuid in ('".implode("','", array_map('mysql_real_escape_string', array_keys($dict)))."')
|
||||
");
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$dict[$row['uuid']] = $row['user_id'];
|
||||
$vars['user_uuid_to_internal_id'] = &$dict;
|
||||
unset($dict);
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/xml; charset=utf-8";
|
||||
$response->content_disposition = 'attachment; filename="results.gpx"';
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?
|
||||
|
||||
namespace okapi\services\caches\formatters\gpx;
|
||||
|
||||
namespace okapi\services\caches\formatters\gpx;
|
||||
|
||||
use okapi\Okapi;
|
||||
|
||||
echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
|
||||
@ -12,12 +12,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd
|
||||
http://www.opencaching.com/xmlschemas/opencaching/1/0 http://www.opencaching.com/xmlschemas/opencaching/1/0/opencaching.xsd
|
||||
http://www.groundspeak.com/cache/1/0 http://www.groundspeak.com/cache/1/0/cache.xsd
|
||||
http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd
|
||||
http://geocaching.com.au/geocache/1 http://geocaching.com.au/geocache/1/geocache.xsd
|
||||
http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
">
|
||||
<name><?= $vars['installation']['site_name'] ?> Geocache Search Results</name>
|
||||
<desc><?= $vars['installation']['site_name'] ?> Geocache Search Results, downloaded via OKAPI - <?= $vars['installation']['okapi_base_url'] ?></desc>
|
||||
<desc><?= $vars['installation']['site_name'] ?> Geocache Search Results, downloaded via OKAPI - <?= $vars['installation']['okapi_base_url'] . ($vars['alt_wpts'] && $vars['ns_gsak'] ? ' (HasChildren)' : '') ?></desc>
|
||||
<author><?= $vars['installation']['site_name'] ?></author>
|
||||
<url><?= $vars['installation']['site_url'] ?></url>
|
||||
<urlname><?= $vars['installation']['site_name'] ?></urlname>
|
||||
@ -37,7 +37,7 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<groundspeak:cache archived="<?= ($c['status'] == 'Archived') ? "True" : "False" ?>" available="<?= ($c['status'] == 'Available') ? "True" : "False" ?>" id="<?= $c['internal_id'] ?>" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0/1">
|
||||
<groundspeak:name><?= Okapi::xmlescape($c['name']) ?></groundspeak:name>
|
||||
<groundspeak:placed_by><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:placed_by>
|
||||
<groundspeak:owner id="<?= $c['owner']['uuid'] ?>"><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:owner>
|
||||
<groundspeak:owner id="<?= $vars['user_uuid_to_internal_id'][$c['owner']['uuid']] ?>"><?= Okapi::xmlescape($c['owner']['username']) ?></groundspeak:owner>
|
||||
<groundspeak:type><?= $vars['cache_GPX_types'][$c['type']] ?></groundspeak:type>
|
||||
<groundspeak:container><?= $vars['cache_GPX_sizes'][$c['size2']] ?></groundspeak:container>
|
||||
<groundspeak:difficulty><?= $c['difficulty'] ?></groundspeak:difficulty>
|
||||
@ -57,7 +57,7 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<? if (($vars['my_notes'] == 'desc:text') && ($c['my_notes'] != null)) { /* Does user want us to include personal notes? */ ?>
|
||||
<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? */ ?>
|
||||
<p><?= _("Attributes") ?>:</p>
|
||||
<ul><li><?= implode("</li><li>", $c['attrnames']) ?></li></ul>
|
||||
@ -108,11 +108,11 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<? 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:log id="<?= $log['internal_id'] ?>">
|
||||
<groundspeak:date><?= $log['date'] ?></groundspeak:date>
|
||||
<groundspeak:type><?= $log['type'] ?></groundspeak:type>
|
||||
<groundspeak:finder id="<?= $log['user']['uuid'] ?>"><?= Okapi::xmlescape($log['user']['username']) ?></groundspeak:finder>
|
||||
<groundspeak:text encoded="False"><?= Okapi::xmlescape($log['comment']) ?></groundspeak:text>
|
||||
<groundspeak:finder id="<?= $vars['user_uuid_to_internal_id'][$log['user']['uuid']] ?>"><?= Okapi::xmlescape($log['user']['username']) ?></groundspeak:finder>
|
||||
<groundspeak:text encoded="False"><?= $log['was_recommended'] ? "(*) ": "" ?><?= Okapi::xmlescape($log['comment']) ?></groundspeak:text>
|
||||
</groundspeak:log>
|
||||
<? } ?>
|
||||
</groundspeak:logs>
|
||||
@ -162,9 +162,9 @@ http://www.gsak.net/xmlv1/5 http://www.gsak.net/xmlv1/5/gsak.xsd
|
||||
<sym><?= $wpt['sym'] ?></sym>
|
||||
<type>Waypoint|<?= $wpt['sym'] ?></type>
|
||||
<? if ($vars['ns_gsak']) { ?>
|
||||
<wptExtension xmlns="http://www.gsak.net/xmlv1/5">
|
||||
<Parent><?= $c['code'] ?></Parent>
|
||||
</wptExtension>
|
||||
<gsak:wptExtension xmlns:gsak="http://www.gsak.net/xmlv1/5">
|
||||
<gsak:Parent><?= $c['code'] ?></gsak:Parent>
|
||||
</gsak:wptExtension>
|
||||
<? } ?>
|
||||
</wpt>
|
||||
<? } ?>
|
||||
|
@ -28,13 +28,16 @@ class WebService
|
||||
if (!$langpref) $langpref = "en";
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "code|name|location|type|status";
|
||||
$log_fields = $request->get_parameter('log_fields');
|
||||
if (!$log_fields) $log_fields = "uuid|date|user|type|comment";
|
||||
$lpc = $request->get_parameter('lpc');
|
||||
if (!$lpc) $lpc = 10;
|
||||
$params = array(
|
||||
'cache_codes' => $cache_code,
|
||||
'langpref' => $langpref,
|
||||
'fields' => $fields,
|
||||
'lpc' => $lpc
|
||||
'lpc' => $lpc,
|
||||
'log_fields' => $log_fields
|
||||
);
|
||||
$my_location = $request->get_parameter('my_location');
|
||||
if ($my_location)
|
||||
@ -42,10 +45,10 @@ class WebService
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
if ($user_uuid)
|
||||
$params['user_uuid'] = $user_uuid;
|
||||
|
||||
|
||||
# There's no need to validate the fields/lpc parameters as the 'geocaches'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
|
||||
|
||||
$results = OkapiServiceRunner::call('services/caches/geocaches', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, $params));
|
||||
$result = $results[$cache_code];
|
||||
|
@ -127,7 +127,7 @@
|
||||
<b>null</b> if geocache does not have a container,
|
||||
</li>
|
||||
<li>
|
||||
<p><b>size2</b> - string indicating the size od the container, so called
|
||||
<p><b>size2</b> - string indicating the size of the container, so called
|
||||
"size2 code". One of the following values:
|
||||
'none', 'nano', 'micro', 'small', 'regular', 'large', 'xlarge', 'other'.</p>
|
||||
</li>
|
||||
@ -170,18 +170,24 @@
|
||||
<ul>
|
||||
<li><b>uuid</b> - UUID of the image,</li>
|
||||
<li><b>url</b> - URL of the image,</li>
|
||||
<li><b>thumb_url</b> - URL of a small (thumb) version of the image
|
||||
<b>or null</b> when no thumb is available (e.g. there are no thumbs
|
||||
for spoiler images),</li>
|
||||
<li><b>thumb_url</b> - URL of a small (thumb) version of the image,</li>
|
||||
<li><b>caption</b> - plain-text string, caption of the image,</li>
|
||||
<li><b>unique_caption</b> - plain-text string, to be used as a filename
|
||||
for Garmin's crappy images implementation (currently, they get image
|
||||
caption from the image's filename itself),</li>
|
||||
<li><b>is_spoiler</b> - boolean, if <b>true</b> then the image is
|
||||
a spoiler image and should not be displayed to the user unless
|
||||
the user explicitly asks for it.</li>
|
||||
the user explicitly asks for it,</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>preview_image</b> - This is either <b>null</b> or a dictionary describing
|
||||
an image, which has been marked by the owner as <em>preview image</em>. You are
|
||||
encouraged to display it as a 'teaser' for this cache.
|
||||
The structure of the dictionary is the same as in the <b>images</b> field above.</p>
|
||||
<p>The preview image is no additional image but one of those which
|
||||
are included in the <b>images</b> list.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>attrnames</b> - list of names of attributes of the cache; the language will
|
||||
be selected based on the <b>langpref</b> argument.</p>
|
||||
@ -216,7 +222,7 @@
|
||||
<p><b>alt_wpts</b> - list of alternate/additional waypoints associated
|
||||
with this geocache. Each item is a dictionary of the following structure:</p>
|
||||
<ul>
|
||||
<li><b>name</b> - plain-text "codename" for the waypoint (not unique),</li>
|
||||
<li><b>name</b> - plain-text, short, unique "codename" for the waypoint,</li>
|
||||
<li><b>location</b> - location of the waypoint in the "lat|lon" format
|
||||
(<i>lat</i> and <i>lon</i> are in full degrees with a dot as a decimal point),</li>
|
||||
<li>
|
||||
@ -267,6 +273,10 @@
|
||||
This should be an integer or a special "all" value. Please note, that you must include
|
||||
the <b>latest_logs</b> field in <b>fields</b> in order to see the log entries.
|
||||
</opt>
|
||||
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
||||
Pipe-separated list of log fields to include in the <b>latest_logs</b> field.
|
||||
For valid field names, see <b>logs/entry</b> method.
|
||||
</opt>
|
||||
<opt name='my_location'>
|
||||
<p>The reference point for cache distance and bearing calculation (typically - the user's location),
|
||||
in the "lat|lon" format. This parameter is required when accessing <b>distance</b> and/or <b>bearing</b>
|
||||
|
@ -31,7 +31,7 @@ class WebService
|
||||
'descriptions', 'hint', 'hints', 'images', 'attrnames', 'latest_logs',
|
||||
'my_notes', 'trackables_count', 'trackables', 'alt_wpts', 'last_found',
|
||||
'last_modified', 'date_created', 'date_hidden', 'internal_id', 'is_watched',
|
||||
'is_ignored', 'willattends', 'country', 'state');
|
||||
'is_ignored', 'willattends', 'country', 'state', 'preview_image');
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
@ -63,6 +63,20 @@ class WebService
|
||||
if (!in_array($field, self::$valid_field_names))
|
||||
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
||||
|
||||
# Currently, the "owner" field needs to be included whenever the "description" field is.
|
||||
# That's a little ugly. Grep for "issue 178" below for more insight on this.
|
||||
if (
|
||||
(
|
||||
in_array('description', $fields) || in_array('descriptions', $fields)
|
||||
|| in_array('hint', $fields) || in_array('hints', $fields)
|
||||
)
|
||||
&& !in_array('owner', $fields)
|
||||
)
|
||||
$fields[] = "owner";
|
||||
|
||||
$log_fields = $request->get_parameter('log_fields');
|
||||
if (!$log_fields) $log_fields = "uuid|date|user|type|comment"; // validation is done on call
|
||||
|
||||
$user_uuid = $request->get_parameter('user_uuid');
|
||||
if ($user_uuid != null)
|
||||
{
|
||||
@ -120,7 +134,7 @@ class WebService
|
||||
|
||||
$rs = Db::query("
|
||||
select
|
||||
c.cache_id, c.name, c.longitude, c.latitude, c.last_modified,
|
||||
c.cache_id, c.name, c.longitude, c.latitude, c.listing_last_modified as last_modified,
|
||||
c.date_created, c.type, c.status, c.date_hidden, c.size, c.difficulty,
|
||||
c.terrain, c.wp_oc, c.logpw, c.user_id,
|
||||
|
||||
@ -258,6 +272,7 @@ class WebService
|
||||
case 'hint': /* handled separately */ break;
|
||||
case 'hints': /* handled separately */ break;
|
||||
case 'images': /* handled separately */ break;
|
||||
case 'preview_image': /* handled separately */ break;
|
||||
case 'attrnames': /* handled separately */ break;
|
||||
case 'latest_logs': /* handled separately */ break;
|
||||
case 'my_notes': /* handles separately */ break;
|
||||
@ -421,8 +436,19 @@ class WebService
|
||||
$cache_code = $cacheid2wptcode[$row['cache_id']];
|
||||
// strtolower - ISO 639-1 codes are lowercase
|
||||
if ($row['desc'])
|
||||
$results[$cache_code]['descriptions'][strtolower($row['language'])] = $row['desc'].
|
||||
"\n".self::get_cache_attribution_note($row['cache_id'], strtolower($row['language']));
|
||||
{
|
||||
/* Regarding the attribution note - please note, that the "owner" field
|
||||
* is automatically included, whenever the cache description is included.
|
||||
* This is because we may need it for the attribution note - see issue 178. */
|
||||
|
||||
$results[$cache_code]['descriptions'][strtolower($row['language'])] = (
|
||||
$row['desc']."\n".
|
||||
self::get_cache_attribution_note(
|
||||
$row['cache_id'], strtolower($row['language']), $langpref,
|
||||
$results[$cache_code]['owner']
|
||||
)
|
||||
);
|
||||
}
|
||||
if ($row['hint'])
|
||||
$results[$cache_code]['hints'][strtolower($row['language'])] = $row['hint'];
|
||||
}
|
||||
@ -442,19 +468,28 @@ class WebService
|
||||
|
||||
# Images.
|
||||
|
||||
if (in_array('images', $fields))
|
||||
if (in_array('images', $fields) || in_array('preview_image', $fields))
|
||||
{
|
||||
foreach ($results as &$result_ref)
|
||||
$result_ref['images'] = array();
|
||||
if (in_array('images', $fields))
|
||||
foreach ($results as &$result_ref)
|
||||
$result_ref['images'] = array();
|
||||
if (in_array('preview_image', $fields))
|
||||
foreach ($results as &$result_ref)
|
||||
$result_ref['preview_image'] = null;
|
||||
|
||||
if (Db::field_exists('pictures', 'mappreview'))
|
||||
$preview_field = "mappreview";
|
||||
else
|
||||
$preview_field = "0";
|
||||
$rs = Db::query("
|
||||
select object_id, uuid, url, thumb_url, title, spoiler
|
||||
select object_id, uuid, url, title, spoiler, ".$preview_field." as preview
|
||||
from pictures
|
||||
where
|
||||
object_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($cacheid2wptcode)))."')
|
||||
and display = 1
|
||||
and object_type = 2
|
||||
and unknown_format = 0
|
||||
order by object_id, last_modified
|
||||
order by object_id, date_created
|
||||
");
|
||||
$prev_cache_code = null;
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
@ -466,14 +501,18 @@ class WebService
|
||||
self::reset_unique_captions();
|
||||
$prev_cache_code = $cache_code;
|
||||
}
|
||||
$results[$cache_code]['images'][] = array(
|
||||
$image = array(
|
||||
'uuid' => $row['uuid'],
|
||||
'url' => $row['url'],
|
||||
'thumb_url' => $row['thumb_url'] ? $row['thumb_url'] : null,
|
||||
'thumb_url' => Settings::get('SITE_URL') . 'thumbs.php?uuid=' . $row['uuid'],
|
||||
'caption' => $row['title'],
|
||||
'unique_caption' => self::get_unique_caption($row['title']),
|
||||
'is_spoiler' => ($row['spoiler'] ? true : false),
|
||||
);
|
||||
if (in_array('images', $fields))
|
||||
$results[$cache_code]['images'][] = $image;
|
||||
if ($row['preview'] != 0 && in_array('preview_image', $fields))
|
||||
$results[$cache_code]['preview_image'] = $image;
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,13 +556,15 @@ class WebService
|
||||
# technique I could think of...
|
||||
|
||||
$rs = Db::query("
|
||||
select cache_id, id, date
|
||||
select cache_id, uuid, date
|
||||
from cache_logs
|
||||
where
|
||||
cache_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($cacheid2wptcode)))."')
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "deleted = 0" : "true")."
|
||||
order by cache_id, date desc
|
||||
");
|
||||
$logids = array();
|
||||
$loguuids = array();
|
||||
$log2cache_map = array();
|
||||
if ($lpc !== null)
|
||||
{
|
||||
# User wants some of the latest logs.
|
||||
@ -538,7 +579,8 @@ class WebService
|
||||
});
|
||||
for ($i = 0; $i < min(count($rowslist_ref), $lpc); $i++)
|
||||
{
|
||||
$logids[] = $rowslist_ref[$i]['id'];
|
||||
$loguuids[] = $rowslist_ref[$i]['uuid'];
|
||||
$log2cache_map[$rowslist_ref[$i]['uuid']] = $cacheid2wptcode[$rowslist_ref[$i]['cache_id']];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -546,35 +588,46 @@ class WebService
|
||||
{
|
||||
# User wants ALL logs.
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$logids[] = $row['id'];
|
||||
{
|
||||
$loguuids[] = $row['uuid'];
|
||||
$log2cache_map[$row['uuid']] = $cacheid2wptcode[$row['cache_id']];
|
||||
}
|
||||
}
|
||||
|
||||
# Now retrieve text and join.
|
||||
# We need to retrieve logs/entry for each of the $logids. We do this in groups
|
||||
# (there is a limit for log uuids passed to logs/entries method).
|
||||
|
||||
$rs = Db::query("
|
||||
select cl.cache_id, cl.id, 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
|
||||
where
|
||||
cl.id in ('".implode("','", array_map('mysql_real_escape_string', $logids))."')
|
||||
and ".((Settings::get('OC_BRANCH') == 'oc.pl') ? "cl.deleted = 0" : "true")."
|
||||
and cl.user_id = u.user_id
|
||||
order by cl.cache_id, cl.date desc
|
||||
");
|
||||
$cachelogs = array();
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
try
|
||||
{
|
||||
$results[$cacheid2wptcode[$row['cache_id']]]['latest_logs'][] = array(
|
||||
'uuid' => $row['uuid'],
|
||||
'date' => date('c', $row['date']),
|
||||
'user' => array(
|
||||
'uuid' => $row['user_uuid'],
|
||||
'username' => $row['username'],
|
||||
'profile_url' => Settings::get('SITE_URL')."viewprofile.php?userid=".$row['user_id'],
|
||||
),
|
||||
'type' => Okapi::logtypeid2name($row['type']),
|
||||
'comment' => $row['text']
|
||||
);
|
||||
foreach (Okapi::make_groups($loguuids, 500) as $subset)
|
||||
{
|
||||
$entries = OkapiServiceRunner::call(
|
||||
"services/logs/entries",
|
||||
new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array(
|
||||
'log_uuids' => implode("|", $subset),
|
||||
'fields' => $log_fields
|
||||
)
|
||||
)
|
||||
);
|
||||
foreach ($subset as $log_uuid)
|
||||
{
|
||||
if ($entries[$log_uuid])
|
||||
$results[$log2cache_map[$log_uuid]]['latest_logs'][] = $entries[$log_uuid];
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
if (($e instanceof InvalidParam) && ($e->paramName == 'fields'))
|
||||
{
|
||||
throw new InvalidParam('log_fields', $e->whats_wrong_about_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Something is wrong with OUR code. */
|
||||
throw new Exception($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -692,6 +745,8 @@ class WebService
|
||||
{
|
||||
foreach ($results as &$result_ref)
|
||||
$result_ref['alt_wpts'] = array();
|
||||
$cache_codes_escaped_and_imploded = "'".implode("','", array_map('mysql_real_escape_string', array_keys($cacheid2wptcode)))."'";
|
||||
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
{
|
||||
# OCPL uses 'waypoints' table to store additional waypoints. OCPL also have
|
||||
@ -699,7 +754,7 @@ class WebService
|
||||
# of a multicache). Such hidden waypoints are not exposed by OKAPI. A stage
|
||||
# fields is used for ordering and naming.
|
||||
|
||||
$rs = Db::query("
|
||||
$waypoints = Db::select_all("
|
||||
select
|
||||
cache_id, stage, latitude, longitude, `desc`,
|
||||
case type
|
||||
@ -710,7 +765,7 @@ class WebService
|
||||
end as sym
|
||||
from waypoints
|
||||
where
|
||||
cache_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($cacheid2wptcode)))."')
|
||||
cache_id in (".$cache_codes_escaped_and_imploded.")
|
||||
and status = 1
|
||||
order by cache_id, stage, `desc`
|
||||
");
|
||||
@ -720,27 +775,32 @@ class WebService
|
||||
# OCDE uses 'coordinates' table (with type=1) to store additional waypoints.
|
||||
# All waypoints are are public.
|
||||
|
||||
$rs = Db::query("
|
||||
$waypoints = Db::select_all("
|
||||
select
|
||||
cache_id,
|
||||
null as stage,
|
||||
@stage := @stage + 1 as stage,
|
||||
latitude, longitude,
|
||||
description as `desc`,
|
||||
case subtype
|
||||
when 1 then 'Parking Area'
|
||||
when 3 then 'Flag, Blue'
|
||||
when 4 then 'Circle with X'
|
||||
when 5 then 'Diamond, Green'
|
||||
else 'Flag, Green'
|
||||
end as sym
|
||||
from coordinates
|
||||
join (select @stage := 0) s
|
||||
where
|
||||
type = 1
|
||||
and cache_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($cacheid2wptcode)))."')
|
||||
order by cache_id, `desc`
|
||||
and cache_id in (".$cache_codes_escaped_and_imploded.")
|
||||
order by cache_id, id, `desc`
|
||||
");
|
||||
}
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$wpt_format = "%s-%0".strlen(count($waypoints))."d";
|
||||
foreach ($waypoints as $index => $row)
|
||||
{
|
||||
$results[$cacheid2wptcode[$row['cache_id']]]['alt_wpts'][] = array(
|
||||
'name' => $cacheid2wptcode[$row['cache_id']]."-".($row['stage'] ? $row['stage'] : "wpt"),
|
||||
'name' => sprintf($wpt_format, $cacheid2wptcode[$row['cache_id']], $index + 1),
|
||||
'location' => round($row['latitude'], 6)."|".round($row['longitude'], 6),
|
||||
'sym' => $row['sym'],
|
||||
'description' => ($row['stage'] ? _("Stage")." ".$row['stage'].": " : "").$row['desc'],
|
||||
@ -748,15 +808,19 @@ class WebService
|
||||
}
|
||||
}
|
||||
|
||||
# Country and/or state.
|
||||
|
||||
# Country and/or state.
|
||||
|
||||
if (Settings::get('OC_BRANCH') == 'oc.de')
|
||||
$cache_location_state = 'adm2';
|
||||
else
|
||||
$cache_location_state = 'adm3';
|
||||
if (in_array('country', $fields) || in_array('state', $fields))
|
||||
{
|
||||
$rs = Db::query("
|
||||
select
|
||||
c.wp_oc as cache_code,
|
||||
cl.adm1 as country,
|
||||
cl.adm3 as state
|
||||
cl.".$cache_location_state." as state
|
||||
from
|
||||
caches c,
|
||||
cache_location cl
|
||||
@ -845,22 +909,54 @@ class WebService
|
||||
self::$caption_no = 1;
|
||||
}
|
||||
|
||||
public static function get_cache_attribution_note($cache_id, $lang)
|
||||
/**
|
||||
* Return attribution note to be included in the cache description.
|
||||
*
|
||||
* The $lang parameter identifies the language of the cache description
|
||||
* to which the attribution note will be appended to (one cache may
|
||||
* have descriptions in multiple languages!).
|
||||
*
|
||||
* The $langpref parameter is *an array* of language preferences
|
||||
* extracted from the langpref parameter passed to the method by the
|
||||
* OKAPI Consumer.
|
||||
*
|
||||
* Both values ($lang and $langpref) will be taken into account when
|
||||
* generating the attribution note, but $lang will have a higher
|
||||
* priority than $langpref (we don't want to mix the languages in the
|
||||
* descriptions if we don't have to).
|
||||
*
|
||||
* $owner is in object describing the user, it has the same format as
|
||||
* defined in "geocache" method specs (see the "owner" field).
|
||||
*/
|
||||
public static function get_cache_attribution_note($cache_id, $lang, array $langpref, $owner)
|
||||
{
|
||||
$site_url = Settings::get('SITE_URL');
|
||||
$site_name = Okapi::get_normalized_site_name();
|
||||
$cache_url = $site_url."viewcache.php?cacheid=$cache_id";
|
||||
|
||||
# This list if to be extended (opencaching.de, etc.). (_)
|
||||
|
||||
switch ($lang)
|
||||
Okapi::gettext_domain_init(array_merge(array($lang), $langpref));
|
||||
$note = "<p>";
|
||||
if (Settings::get('OC_BRANCH') == 'oc.de')
|
||||
{
|
||||
case 'pl':
|
||||
return "<p>Opis <a href='$cache_url'>skrzynki</a> pochodzi z serwisu <a href='$site_url'>$site_name</a>.</p>";
|
||||
break;
|
||||
default:
|
||||
return "<p>This <a href='$cache_url'>geocache</a> description comes from the <a href='$site_url'>$site_name</a> site.</p>";
|
||||
break;
|
||||
$note .= sprintf(
|
||||
_(
|
||||
"<em>© <a href='%s'>%s</a>, <a href='%s'>%s</a>, ".
|
||||
"<a href='http://creativecommons.org/licenses/by-nc-nd/3.0/de/deed.en'>CC-BY-NC-ND</a>, ".
|
||||
"as of %s; all log entries © their authors</em>"
|
||||
),
|
||||
$owner['profile_url'], $owner['username'], $cache_url, $site_name, strftime('%x')
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$note .= sprintf(
|
||||
_("This <a href='%s'>geocache</a> description comes from the <a href='%s'>%s</a> site."),
|
||||
$cache_url, $site_url, $site_name
|
||||
);
|
||||
}
|
||||
$note .= "</p>";
|
||||
Okapi::gettext_domain_restore();
|
||||
|
||||
return $note;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,9 @@
|
||||
<opt name='lpc' default='10'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<opt name='log_fields' default='uuid|date|user|type|comment'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
<opt name='user_uuid'>
|
||||
Same as in the services/caches/geocache method.
|
||||
</opt>
|
||||
|
@ -28,7 +28,7 @@ class ReplicateListener
|
||||
# This will be called every time new items arrive from replicate module's
|
||||
# changelog. The format of $changelog is described in the replicate module
|
||||
# (NOT the entire response, just the "changelog" key).
|
||||
|
||||
|
||||
foreach ($changelog as $c)
|
||||
{
|
||||
if ($c['object_type'] == 'geocache')
|
||||
@ -40,38 +40,22 @@ class ReplicateListener
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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!
|
||||
|
||||
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)."
|
||||
);
|
||||
}
|
||||
# For the first hours after such reset maps may work a little slower.
|
||||
|
||||
Db::execute("delete from okapi_tile_status");
|
||||
Db::execute("delete from okapi_tile_caches");
|
||||
}
|
||||
|
||||
|
||||
private static function handle_geocache_replace($c)
|
||||
{
|
||||
# Check if any relevant geocache attributes have changed.
|
||||
# We will pick up "our" copy of the cache from zero-zoom level.
|
||||
|
||||
|
||||
try {
|
||||
$cache = OkapiServiceRunner::call("services/caches/geocache", new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
||||
'cache_code' => $c['object_key']['code'],
|
||||
@ -81,7 +65,7 @@ class ReplicateListener
|
||||
# Unprobable, but possible. Ignore changelog entry.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$theirs = TileTree::generate_short_row($cache);
|
||||
$ours = mysql_fetch_row(Db::query("
|
||||
select cache_id, z21x, z21y, status, type, rating, flags
|
||||
@ -93,13 +77,13 @@ class ReplicateListener
|
||||
if (!$ours)
|
||||
{
|
||||
# Aaah, a new geocache! How nice... ;)
|
||||
|
||||
|
||||
self::add_geocache_to_cached_tiles($theirs);
|
||||
}
|
||||
elseif (($ours[1] != $theirs[1]) || ($ours[2] != $theirs[2])) # z21x & z21y fields
|
||||
{
|
||||
# Location changed.
|
||||
|
||||
|
||||
self::remove_geocache_from_cached_tiles($ours[0]);
|
||||
self::add_geocache_to_cached_tiles($theirs);
|
||||
}
|
||||
@ -114,23 +98,23 @@ class ReplicateListener
|
||||
# many updates which do not influence our cache.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function remove_geocache_from_cached_tiles($cache_id)
|
||||
{
|
||||
# Simply remove all traces of this geocache from all tiles.
|
||||
# This includes all references along tiles' borders, etc.
|
||||
|
||||
|
||||
Db::execute("
|
||||
delete from okapi_tile_caches
|
||||
where cache_id = '".mysql_real_escape_string($cache_id)."'
|
||||
");
|
||||
|
||||
|
||||
# Note, that after this operation, okapi_tile_status may be out-of-date.
|
||||
# There might exist some rows with status==2, but they should be in status==1.
|
||||
# Currently, we can ignore this, because status==1 is just a shortcut to
|
||||
# avoid making unnecessary queries.
|
||||
}
|
||||
|
||||
|
||||
private static function add_geocache_to_cached_tiles(&$row)
|
||||
{
|
||||
# This one is the most complicated. We need to identify all tiles
|
||||
@ -138,11 +122,11 @@ class ReplicateListener
|
||||
# tiles (one per each zoom level), *and* all "just outside the border"
|
||||
# tiles (one geocache can be present in up to 4 tiles per zoom level).
|
||||
# This gives us max. 88 tiles to add the geocache to.
|
||||
|
||||
|
||||
$tiles_to_update = array();
|
||||
|
||||
|
||||
# We will begin at zoom 21 and then go down to zoom 0.
|
||||
|
||||
|
||||
$z21x = $row[1];
|
||||
$z21y = $row[2];
|
||||
$ex = $z21x >> 8; # initially, z21x / <tile width>
|
||||
@ -152,25 +136,25 @@ class ReplicateListener
|
||||
# ($ex, $ey) points to the "exact match" tile. We need to determine
|
||||
# tile-range to check for "just outside the border" tiles. We will
|
||||
# go with the simple approach and check all 1+8 bordering tiles.
|
||||
|
||||
|
||||
$tiles_in_this_region = array();
|
||||
for ($x=$ex-1; $x<=$ex+1; $x++)
|
||||
for ($y=$ey-1; $y<=$ey+1; $y++)
|
||||
if (($x >= 0) && ($x < 1<<$zoom) && ($y >= 0) && ($y < 1<<$zoom))
|
||||
$tiles_in_this_region[] = array($x, $y);
|
||||
|
||||
|
||||
foreach ($tiles_in_this_region as $coords)
|
||||
{
|
||||
list($x, $y) = $coords;
|
||||
|
||||
|
||||
$scale = 8 + 21 - $zoom;
|
||||
$margin = 1 << ($scale - 3); # 32px of current $zoom level, measured in z21 pixels.
|
||||
|
||||
|
||||
$left_z21x = ($x << $scale) - $margin;
|
||||
$right_z21x = (($x + 1) << $scale) + $margin;
|
||||
$top_z21y = ($y << $scale) - $margin;
|
||||
$bottom_z21y = (($y + 1) << $scale) + $margin;
|
||||
|
||||
|
||||
if ($z21x < $left_z21x)
|
||||
continue;
|
||||
if ($z21x > $right_z21x)
|
||||
@ -179,17 +163,17 @@ class ReplicateListener
|
||||
continue;
|
||||
if ($z21y > $bottom_z21y)
|
||||
continue;
|
||||
|
||||
|
||||
# We found a match. Store it for later.
|
||||
|
||||
|
||||
$tiles_to_update[] = array($zoom, $x, $y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# We have a list of all possible tiles that need updating.
|
||||
# Most of these tiles aren't cached at all. We need to update
|
||||
# only the cached ones.
|
||||
|
||||
|
||||
$alternatives = array();
|
||||
foreach ($tiles_to_update as $coords)
|
||||
{
|
||||
@ -200,45 +184,48 @@ class ReplicateListener
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
)";
|
||||
}
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
)
|
||||
select
|
||||
z, x, y,
|
||||
'".mysql_real_escape_string($row[0])."',
|
||||
'".mysql_real_escape_string($row[1])."',
|
||||
'".mysql_real_escape_string($row[2])."',
|
||||
'".mysql_real_escape_string($row[3])."',
|
||||
'".mysql_real_escape_string($row[4])."',
|
||||
".(($row[5] === null) ? "null" : $row[5]).",
|
||||
'".mysql_real_escape_string($row[6])."'
|
||||
from okapi_tile_status
|
||||
where
|
||||
(".implode(" or ", $alternatives).")
|
||||
and status in (1,2)
|
||||
");
|
||||
|
||||
# We might have just filled some empty tiles (status 1) with data.
|
||||
# We need to update their status to 2.
|
||||
|
||||
Db::execute("
|
||||
update okapi_tile_status
|
||||
set status=2
|
||||
where
|
||||
(".implode(" or ", $alternatives).")
|
||||
and status=1
|
||||
");
|
||||
|
||||
if (count($alternatives) > 0)
|
||||
{
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
)
|
||||
select
|
||||
z, x, y,
|
||||
'".mysql_real_escape_string($row[0])."',
|
||||
'".mysql_real_escape_string($row[1])."',
|
||||
'".mysql_real_escape_string($row[2])."',
|
||||
'".mysql_real_escape_string($row[3])."',
|
||||
'".mysql_real_escape_string($row[4])."',
|
||||
".(($row[5] === null) ? "null" : $row[5]).",
|
||||
'".mysql_real_escape_string($row[6])."'
|
||||
from okapi_tile_status
|
||||
where
|
||||
(".implode(" or ", $alternatives).")
|
||||
and status in (1,2)
|
||||
");
|
||||
|
||||
# We might have just filled some empty tiles (status 1) with data.
|
||||
# We need to update their status to 2.
|
||||
|
||||
Db::execute("
|
||||
update okapi_tile_status
|
||||
set status=2
|
||||
where
|
||||
(".implode(" or ", $alternatives).")
|
||||
and status=1
|
||||
");
|
||||
}
|
||||
|
||||
# And that's all. That should do the trick.
|
||||
}
|
||||
|
||||
|
||||
private static function update_geocache_attributes_in_cached_tiles(&$row)
|
||||
{
|
||||
# Update all attributes (for all levels). Note, that we don't need to
|
||||
# update location ($row[1] and $row[2]) - this method is called ONLY
|
||||
# when location stayed untouched!
|
||||
|
||||
|
||||
Db::execute("
|
||||
update okapi_tile_caches
|
||||
set
|
||||
@ -250,11 +237,11 @@ class ReplicateListener
|
||||
cache_id = '".mysql_real_escape_string($row[0])."'
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function handle_geocache_delete($c)
|
||||
{
|
||||
# Simply delete the cache at all zoom levels.
|
||||
|
||||
|
||||
$cache_id = Db::select_value("
|
||||
select cache_id
|
||||
from caches
|
||||
|
@ -34,26 +34,26 @@ class WebService
|
||||
* testing/debugging the tile renderer.
|
||||
*/
|
||||
private static $USE_ETAGS_CACHE = true;
|
||||
|
||||
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging the tile renderer.
|
||||
*/
|
||||
private static $USE_IMAGE_CACHE = true;
|
||||
|
||||
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging. Grep the code to check when this flag is used.
|
||||
*/
|
||||
private static $USE_OTHER_CACHE = true;
|
||||
|
||||
|
||||
public static function options()
|
||||
{
|
||||
return array(
|
||||
'min_auth_level' => 3
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static function require_uint($request, $name, $min_value = 0)
|
||||
{
|
||||
$val = $request->get_parameter($name);
|
||||
@ -64,18 +64,18 @@ class WebService
|
||||
throw new InvalidParam($name, "Expecting non-negative integer.");
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$checkpointA_started = microtime(true);
|
||||
|
||||
|
||||
# Make sure the request is internal.
|
||||
|
||||
|
||||
if (!in_array($request->consumer->key, array('internal', 'facade')))
|
||||
throw new BadRequest("Your Consumer Key has not been allowed to access this method.");
|
||||
|
||||
|
||||
# zoom, x, y - required tile-specific parameters.
|
||||
|
||||
|
||||
$zoom = self::require_uint($request, 'z');
|
||||
if ($zoom > 21)
|
||||
throw new InvalidParam('z', "Maximum value for this parameter is 21.");
|
||||
@ -85,18 +85,18 @@ class WebService
|
||||
throw new InvalidParam('x', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||
if ($y >= 1<<$zoom)
|
||||
throw new InvalidParam('y', "Should be in 0..".((1<<$zoom) - 1).".");
|
||||
|
||||
|
||||
# Now, we will create a search set (or use one previously created).
|
||||
# Instead of creating a new OkapiInternalRequest object, we will pass
|
||||
# the current request directly. We can do that, because we inherit all
|
||||
# of the "save" method's parameters.
|
||||
|
||||
|
||||
$search_set = OkapiServiceRunner::call('services/caches/search/save', $request);
|
||||
$set_id = $search_set['set_id'];
|
||||
|
||||
|
||||
# Get caches which are present in the result set AND within the tile
|
||||
# (+ those around the borders).
|
||||
|
||||
|
||||
$rs = TileTree::query_fast($zoom, $x, $y, $set_id);
|
||||
$rows = array();
|
||||
if ($rs !== null)
|
||||
@ -110,19 +110,19 @@ class WebService
|
||||
$checkpointB_started = microtime(true);
|
||||
|
||||
# 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
|
||||
@ -131,9 +131,9 @@ class WebService
|
||||
$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
|
||||
@ -147,7 +147,7 @@ class WebService
|
||||
$user['found'][$cache_id] = true;
|
||||
|
||||
# Own caches.
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select distinct cache_id
|
||||
from caches
|
||||
@ -156,12 +156,12 @@ class WebService
|
||||
$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
|
||||
@ -174,36 +174,36 @@ class WebService
|
||||
$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);
|
||||
$image_fingerprint = $tile->get_unique_hash();
|
||||
|
||||
|
||||
# Start creating response.
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = $tile->get_content_type();
|
||||
$response->cache_control = "Cache-Control: private, max-age=600";
|
||||
$response->etag = 'W/"'.$image_fingerprint.'"';
|
||||
|
||||
|
||||
# Check if the request didn't include the same ETag.
|
||||
|
||||
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointB", null,
|
||||
microtime(true) - $checkpointB_started);
|
||||
$checkpointC_started = microtime(true);
|
||||
if (self::$USE_ETAGS_CACHE && ($request->etag == $response->etag))
|
||||
{
|
||||
# Hit. Report the content was unmodified.
|
||||
|
||||
|
||||
$response->etag = null;
|
||||
$response->status = "304 Not Modified";
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
# Check if the image was recently rendered and is kept in image cache.
|
||||
|
||||
|
||||
$cache_key = "tile/".$image_fingerprint;
|
||||
$response->body = self::$USE_IMAGE_CACHE ? Cache::get($cache_key) : null;
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointC", null,
|
||||
@ -212,12 +212,12 @@ class WebService
|
||||
if ($response->body !== null)
|
||||
{
|
||||
# Hit. We will use the cached version of the image.
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
# Miss. Render the image. Cache the result.
|
||||
|
||||
|
||||
$response->body = $tile->render();
|
||||
Cache::set_scored($cache_key, $response->body);
|
||||
OkapiServiceRunner::save_stats_extra("caches/map/tile/checkpointD", null,
|
||||
|
@ -17,10 +17,10 @@ interface TileRenderer
|
||||
* throw an Exception on every subsequent call.
|
||||
*/
|
||||
public function get_unique_hash();
|
||||
|
||||
|
||||
/** Get the content type of the data returned by the render method. */
|
||||
public function get_content_type();
|
||||
|
||||
|
||||
/**
|
||||
* Render the image. This function will be called only once, after calling
|
||||
* get_unique_hash method.
|
||||
@ -35,23 +35,23 @@ class DefaultTileRenderer implements TileRenderer
|
||||
* whenever you alter anything in the drawing algorithm.
|
||||
*/
|
||||
private static $VERSION = 56;
|
||||
|
||||
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging a new set of static icons.
|
||||
*/
|
||||
private static $USE_STATIC_IMAGE_CACHE = true;
|
||||
|
||||
|
||||
/**
|
||||
* Should be always true. You may temporarily set it to false, when you're
|
||||
* testing/debugging a new captions renderer.
|
||||
*/
|
||||
private static $USE_CAPTIONS_CACHE = true;
|
||||
|
||||
|
||||
private $zoom;
|
||||
private $rows_ref;
|
||||
private $im;
|
||||
|
||||
|
||||
/**
|
||||
* Takes the zoom level and the list of geocache descriptions. Note, that
|
||||
* $rows_ref can be altered after calling render. If you don't want it to,
|
||||
@ -62,7 +62,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$this->zoom = $zoom;
|
||||
$this->rows_ref = &$rows_ref;
|
||||
}
|
||||
|
||||
|
||||
public function get_unique_hash()
|
||||
{
|
||||
return md5(json_encode(array(
|
||||
@ -72,21 +72,21 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$this->rows_ref
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
public function get_content_type()
|
||||
{
|
||||
return "image/png";
|
||||
}
|
||||
|
||||
|
||||
public function render()
|
||||
{
|
||||
# Preprocess the rows.
|
||||
|
||||
|
||||
if ($this->zoom >= 5)
|
||||
$this->decide_which_get_captions();
|
||||
|
||||
|
||||
# Make a background.
|
||||
|
||||
|
||||
$this->im = imagecreatetruecolor(256, 256);
|
||||
imagealphablending($this->im, false);
|
||||
if ($this->zoom >= 13) $opacity = 15;
|
||||
@ -94,33 +94,33 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$transparent = imagecolorallocatealpha($this->im, 0, 0, 0, 127 - $opacity);
|
||||
imagefilledrectangle($this->im, 0, 0, 256, 256, $transparent);
|
||||
imagealphablending($this->im, true);
|
||||
|
||||
|
||||
# Draw the caches.
|
||||
|
||||
|
||||
foreach ($this->rows_ref as &$row_ref)
|
||||
$this->draw_cache($row_ref);
|
||||
|
||||
|
||||
# Return the result.
|
||||
|
||||
|
||||
ob_start();
|
||||
imagesavealpha($this->im, true);
|
||||
imagepng($this->im);
|
||||
imagedestroy($this->im);
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
|
||||
private static function get_image($name, $opacity=1, $brightness=0,
|
||||
$contrast=0, $r=0, $g=0, $b=0)
|
||||
{
|
||||
static $locmem_cache = array();
|
||||
|
||||
# Check locmem cache.
|
||||
|
||||
|
||||
$key = "$name/$opacity/$brightness/$contrast/$r/$g/$b";
|
||||
if (!isset($locmem_cache[$key]))
|
||||
{
|
||||
# Miss. Check default cache. WRTODO: upgrade to normal Cache?
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
$cache_key = "tilesrc/".Okapi::$revision."/".self::$VERSION."/".$key;
|
||||
@ -135,11 +135,11 @@ class DefaultTileRenderer implements TileRenderer
|
||||
catch (Exception $e)
|
||||
{
|
||||
# Miss again (or error decoding). Read the image from PNG.
|
||||
|
||||
|
||||
$locmem_cache[$key] = imagecreatefrompng($GLOBALS['rootpath']."okapi/static/tilemap/$name.png");
|
||||
|
||||
|
||||
# Apply all wanted effects.
|
||||
|
||||
|
||||
if ($opacity != 1)
|
||||
self::change_opacity($locmem_cache[$key], $opacity);
|
||||
if ($contrast != 0)
|
||||
@ -148,12 +148,12 @@ class DefaultTileRenderer implements TileRenderer
|
||||
imagefilter($locmem_cache[$key], IMG_FILTER_BRIGHTNESS, $brightness);
|
||||
if (($r != 0) || ($g != 0) || ($b != 0))
|
||||
{
|
||||
imagefilter($locmem_cache[$key], IMG_FILTER_GRAYSCALE);
|
||||
imagefilter($locmem_cache[$key], IMG_FILTER_GRAYSCALE);
|
||||
imagefilter($locmem_cache[$key], IMG_FILTER_COLORIZE, $r, $g, $b);
|
||||
}
|
||||
|
||||
|
||||
# Cache the result.
|
||||
|
||||
|
||||
ob_start();
|
||||
imagegd2($locmem_cache[$key]);
|
||||
$gd2 = ob_get_clean();
|
||||
@ -169,7 +169,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
private static function change_opacity($im, $ratio)
|
||||
{
|
||||
imagealphablending($im, false);
|
||||
|
||||
|
||||
$w = imagesx($im);
|
||||
$h = imagesy($im);
|
||||
|
||||
@ -182,7 +182,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
imagesetpixel($im, $x, $y, $new_color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
imagealphablending($im, true);
|
||||
}
|
||||
|
||||
@ -197,7 +197,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$this->draw_cache_large($cache_struct);
|
||||
|
||||
# Put caption (this flag is set only when there is plenty of space around).
|
||||
|
||||
|
||||
if ($cache_struct[6] & TileTree::$FLAG_DRAW_CAPTION)
|
||||
{
|
||||
$caption = $this->get_caption($cache_struct[0]);
|
||||
@ -210,13 +210,13 @@ class DefaultTileRenderer implements TileRenderer
|
||||
private function draw_cache_large(&$cache_struct)
|
||||
{
|
||||
list($cache_id, $px, $py, $status, $type, $rating, $flags, $count) = $cache_struct;
|
||||
|
||||
|
||||
$found = $flags & TileTree::$FLAG_FOUND;
|
||||
$own = $flags & TileTree::$FLAG_OWN;
|
||||
$new = $flags & TileTree::$FLAG_NEW;
|
||||
|
||||
|
||||
# Prepare vars.
|
||||
|
||||
|
||||
if ($own) {
|
||||
$key = 'large_outer_own';
|
||||
$a = 1; $br = 0; $c = 0;
|
||||
@ -236,29 +236,29 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$a = 1; $br = 0; $c = 0;
|
||||
$r = 0; $g = 0; $b = 0;
|
||||
}
|
||||
|
||||
|
||||
# Put the outer marker (indicates the found/new/own status).
|
||||
|
||||
|
||||
$outer_marker = self::get_image($key, $a);
|
||||
|
||||
|
||||
$width = 40;
|
||||
$height = 32;
|
||||
$center_x = 12;
|
||||
$center_y = 26;
|
||||
$markercenter_x = 12;
|
||||
$markercenter_y = 12;
|
||||
|
||||
|
||||
if ($count > 1)
|
||||
imagecopy($this->im, $outer_marker, $px - $center_x + 3, $py - $center_y - 2, 0, 0, $width, $height);
|
||||
imagecopy($this->im, $outer_marker, $px - $center_x, $py - $center_y, 0, 0, $width, $height);
|
||||
|
||||
|
||||
# Put the inner marker (indicates the type).
|
||||
|
||||
|
||||
$inner_marker = self::get_image("large_inner_".self::get_type_suffix(
|
||||
$type, true), $a, $br, $c, $r, $g, $b);
|
||||
imagecopy($this->im, $inner_marker, $px - 7, $py - 22, 0, 0, 16, 16);
|
||||
|
||||
# If the cache is unavailable, mark it with X.
|
||||
|
||||
# If the cache is unavailable, mark it with X.
|
||||
|
||||
if (($status != 1) && ($count == 1))
|
||||
{
|
||||
@ -266,9 +266,9 @@ class DefaultTileRenderer implements TileRenderer
|
||||
: "status_archived", $a);
|
||||
imagecopy($this->im, $icon, $px - 1, $py - $center_y - 4, 0, 0, 16, 16);
|
||||
}
|
||||
|
||||
|
||||
# Put the rating smile. :)
|
||||
|
||||
|
||||
if ($status == 1)
|
||||
{
|
||||
if ($rating >= 4.2)
|
||||
@ -289,15 +289,15 @@ class DefaultTileRenderer implements TileRenderer
|
||||
// imagecopy($this->im, $icon, $px - 7, $py - $center_y - 8, 0, 0, 16, 16);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
# Mark found caches with V.
|
||||
|
||||
|
||||
if ($found)
|
||||
{
|
||||
$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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -335,43 +335,43 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$lines[] = trim($line);
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return 64x26 bitmap with the caption (name) for the given geocache.
|
||||
*/
|
||||
private function get_caption($cache_id)
|
||||
{
|
||||
# Check cache.
|
||||
|
||||
|
||||
$cache_key = "tilecaption/".self::$VERSION."/".$cache_id;
|
||||
$gd2 = self::$USE_CAPTIONS_CACHE ? Cache::get($cache_key) : null;
|
||||
if ($gd2 === null)
|
||||
{
|
||||
# We'll work with 16x bigger image to get smoother interpolation.
|
||||
|
||||
|
||||
$im = imagecreatetruecolor(64*4, 26*4);
|
||||
imagealphablending($im, false);
|
||||
imagealphablending($im, false);
|
||||
$transparent = imagecolorallocatealpha($im, 255, 255, 255, 127);
|
||||
imagefilledrectangle($im, 0, 0, 64*4, 26*4, $transparent);
|
||||
imagealphablending($im, true);
|
||||
|
||||
|
||||
# Get the name of the cache.
|
||||
|
||||
|
||||
$name = Db::select_value("
|
||||
select name
|
||||
from caches
|
||||
where cache_id = '".mysql_real_escape_string($cache_id)."'
|
||||
");
|
||||
|
||||
|
||||
# Split the name into a couple of lines.
|
||||
|
||||
|
||||
//$font = $GLOBALS['rootpath'].'util.sec/bt.ttf';
|
||||
$font = $GLOBALS['rootpath'].'okapi/static/tilemap/tahoma.ttf';
|
||||
$size = 25;
|
||||
$lines = explode("\n", self::wordwrap($font, $size, 64*4 - 6*2, $name));
|
||||
|
||||
|
||||
# For each line, compute its (x, y) so that the text is centered.
|
||||
|
||||
|
||||
$y = 0;
|
||||
$positions = array();
|
||||
foreach ($lines as $line)
|
||||
@ -392,44 +392,44 @@ class DefaultTileRenderer implements TileRenderer
|
||||
imagettftext($im, $size, 0, $offset_x + $x, $offset_y + $y, $color, $font, $line);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
# Draw an outline.
|
||||
|
||||
|
||||
$outline_color = imagecolorallocatealpha($im, 255, 255, 255, 80);
|
||||
for ($x=0; $x<=12; $x+=3)
|
||||
for ($y=$size-3; $y<=$size+9; $y+=3)
|
||||
$drawer($x, $y, $outline_color);
|
||||
|
||||
|
||||
# Add a slight shadow effect (on top of the outline).
|
||||
|
||||
|
||||
$drawer(9, $size + 3, imagecolorallocatealpha($im, 0, 0, 0, 110));
|
||||
|
||||
|
||||
# Draw the caption.
|
||||
|
||||
|
||||
$drawer(6, $size + 3, imagecolorallocatealpha($im, 150, 0, 0, 40));
|
||||
|
||||
# Resample.
|
||||
|
||||
imagealphablending($im, false);
|
||||
|
||||
imagealphablending($im, false);
|
||||
$small = imagecreatetruecolor(64, 26);
|
||||
imagealphablending($small, false);
|
||||
imagecopyresampled($small, $im, 0, 0, 0, 0, 64, 26, 64*4, 26*4);
|
||||
|
||||
|
||||
# Cache it!
|
||||
|
||||
|
||||
ob_start();
|
||||
imagegd2($small);
|
||||
$gd2 = ob_get_clean();
|
||||
Cache::set_scored($cache_key, $gd2);
|
||||
}
|
||||
|
||||
|
||||
return imagecreatefromstring($gd2);
|
||||
}
|
||||
|
||||
private function draw_cache_medium(&$cache_struct)
|
||||
{
|
||||
list($cache_id, $px, $py, $status, $type, $rating, $flags, $count) = $cache_struct;
|
||||
|
||||
|
||||
$found = $flags & TileTree::$FLAG_FOUND;
|
||||
$own = $flags & TileTree::$FLAG_OWN;
|
||||
$new = $flags & TileTree::$FLAG_NEW;
|
||||
@ -437,9 +437,9 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$a = .35;
|
||||
else
|
||||
$a = 1;
|
||||
|
||||
|
||||
# Put the marker (indicates the type).
|
||||
|
||||
|
||||
$marker = self::get_image("medium_".self::get_type_suffix($type, false), $a);
|
||||
$width = 14;
|
||||
$height = 14;
|
||||
@ -458,7 +458,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
imagecopy($this->im, $marker, $px - $center_x, $py - $center_y, 0, 0, $width, $height);
|
||||
}
|
||||
|
||||
# If the cache is unavailable, mark it with X.
|
||||
# If the cache is unavailable, mark it with X.
|
||||
|
||||
if (($status != 1) && ($count == 1))
|
||||
{
|
||||
@ -467,9 +467,9 @@ class DefaultTileRenderer implements TileRenderer
|
||||
imagecopy($this->im, $icon, $px - ($center_x - $markercenter_x) - 6,
|
||||
$py - ($center_y - $markercenter_y) - 8, 0, 0, 16, 16);
|
||||
}
|
||||
|
||||
|
||||
# Put small versions of rating icons.
|
||||
|
||||
|
||||
if ($status == 1)
|
||||
{
|
||||
if ($rating >= 4.2)
|
||||
@ -485,18 +485,18 @@ class DefaultTileRenderer implements TileRenderer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($own)
|
||||
{
|
||||
# Mark own caches with additional overlay.
|
||||
|
||||
|
||||
$overlay = self::get_image("medium_overlay_own");
|
||||
imagecopy($this->im, $overlay, $px - $center_x, $py - $center_y, 0, 0, $width, $height);
|
||||
}
|
||||
elseif ($found)
|
||||
{
|
||||
# Mark found caches with V.
|
||||
|
||||
|
||||
$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);
|
||||
@ -504,7 +504,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
elseif ($new)
|
||||
{
|
||||
# Mark new caches with additional overlay.
|
||||
|
||||
|
||||
$overlay = self::get_image("medium_overlay_new");
|
||||
imagecopy($this->im, $overlay, $px - $center_x, $py - $center_y, 0, 0, $width, $height);
|
||||
}
|
||||
@ -530,15 +530,15 @@ class DefaultTileRenderer implements TileRenderer
|
||||
}
|
||||
return 'other';
|
||||
}
|
||||
|
||||
|
||||
private function draw_cache_tiny(&$cache_struct)
|
||||
{
|
||||
list($cache_id, $px, $py, $status, $type, $rating, $flags, $count) = $cache_struct;
|
||||
|
||||
|
||||
$found = $flags & TileTree::$FLAG_FOUND;
|
||||
$own = $flags & TileTree::$FLAG_OWN;
|
||||
$new = $flags & TileTree::$FLAG_NEW;
|
||||
|
||||
|
||||
$marker = self::get_image("tiny_".self::get_type_suffix($type, false));
|
||||
$width = 10;
|
||||
$height = 10;
|
||||
@ -546,9 +546,9 @@ class DefaultTileRenderer implements TileRenderer
|
||||
$center_y = 6;
|
||||
$markercenter_x = 5;
|
||||
$markercenter_y = 6;
|
||||
|
||||
|
||||
# Put the marker. If cache covers more caches, then put two markers instead of one.
|
||||
|
||||
|
||||
if ($count > 1)
|
||||
{
|
||||
imagecopy($this->im, $marker, $px - $center_x + 3, $py - $center_y - 2, 0, 0, $width, $height);
|
||||
@ -559,7 +559,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
imagecopy($this->im, $marker, $px - $center_x, $py - $center_y, 0, 0, $width, $height);
|
||||
}
|
||||
|
||||
# If the cache is unavailable, mark it with X.
|
||||
# If the cache is unavailable, mark it with X.
|
||||
|
||||
if (($status != 1) && ($count == 1))
|
||||
{
|
||||
@ -582,11 +582,11 @@ class DefaultTileRenderer implements TileRenderer
|
||||
# A single geocache placed in square (x, y) gets the caption only
|
||||
# when there are no other geocaches in any of the adjacent squares.
|
||||
# This is efficient and yields acceptable results.
|
||||
|
||||
|
||||
$matrix = array();
|
||||
for ($i=0; $i<12; $i++)
|
||||
$matrix[] = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
|
||||
foreach ($this->rows_ref as &$row_ref)
|
||||
{
|
||||
$mx = ($row_ref[1] + 64) >> 5;
|
||||
@ -605,7 +605,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
if ($matrix[$mx][$my] > 0) # cache_id
|
||||
{
|
||||
# Check all adjacent squares.
|
||||
|
||||
|
||||
if ( ($matrix[$mx-1][$my-1] === 0)
|
||||
&& ($matrix[$mx-1][$my ] === 0)
|
||||
&& ($matrix[$mx-1][$my+1] === 0)
|
||||
@ -619,7 +619,7 @@ class DefaultTileRenderer implements TileRenderer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->rows_ref as &$row_ref)
|
||||
if (in_array($row_ref[0], $selected_cache_ids))
|
||||
$row_ref[6] |= TileTree::$FLAG_DRAW_CAPTION;
|
||||
|
@ -25,13 +25,13 @@ class TileTree
|
||||
public static $FLAG_STAR = 0x01;
|
||||
public static $FLAG_HAS_TRACKABLES = 0x02;
|
||||
public static $FLAG_NOT_YET_FOUND = 0x04;
|
||||
|
||||
|
||||
# Dynamic flags (added at runtime).
|
||||
public static $FLAG_FOUND = 0x0100;
|
||||
public static $FLAG_OWN = 0x0200;
|
||||
public static $FLAG_NEW = 0x0400;
|
||||
public static $FLAG_DRAW_CAPTION = 0x0800;
|
||||
|
||||
|
||||
/**
|
||||
* Return null if not computed, 1 if computed and empty, 2 if computed and not empty.
|
||||
*/
|
||||
@ -46,7 +46,7 @@ class TileTree
|
||||
and y = '".mysql_real_escape_string($y)."'
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return MySQL's result set iterator over all caches which are present
|
||||
* in the given result set AND in the given tile.
|
||||
@ -62,27 +62,27 @@ class TileTree
|
||||
{
|
||||
# First, we check if the cache-set for this tile was already computed
|
||||
# (and if it was, was it empty).
|
||||
|
||||
|
||||
$status = self::get_tile_status($zoom, $x, $y);
|
||||
if ($status === null) # Not yet computed.
|
||||
{
|
||||
# Note, that computing the tile does not involve taking any
|
||||
# search parameters.
|
||||
|
||||
|
||||
$status = self::compute_tile($zoom, $x, $y);
|
||||
}
|
||||
|
||||
|
||||
if ($status === 1) # Computed and empty.
|
||||
{
|
||||
# This tile was already computed and it is empty.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
# If we got here, then the tile is computed and not empty (status 2).
|
||||
|
||||
|
||||
$tile_upper_x = $x << 8;
|
||||
$tile_leftmost_y = $y << 8;
|
||||
|
||||
|
||||
return Db::query("
|
||||
select
|
||||
otc.cache_id,
|
||||
@ -106,14 +106,14 @@ class TileTree
|
||||
z21x >> (3 + (21 - $zoom))
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Precache the ($zoom, $x, $y) slot in the okapi_tile_caches table.
|
||||
*/
|
||||
public static function compute_tile($zoom, $x, $y)
|
||||
{
|
||||
$time_started = microtime(true);
|
||||
|
||||
|
||||
# Note, that multiple threads may try to compute tiles simulatanously.
|
||||
# For low-level tiles, this can be expensive. WRTODO: Think of some
|
||||
# appropriate locks.
|
||||
@ -121,33 +121,33 @@ class TileTree
|
||||
$status = self::get_tile_status($zoom, $x, $y);
|
||||
if ($status !== null)
|
||||
return $status;
|
||||
|
||||
|
||||
if ($zoom === 0)
|
||||
{
|
||||
# When computing zoom zero, we don't have a parent to speed up
|
||||
# the computation. We need to use the caches table. Note, that
|
||||
# zoom level 0 contains *entire world*, so we don't have to use
|
||||
# any WHERE condition in the following query.
|
||||
|
||||
|
||||
# This can be done a little faster (without the use of internal requests),
|
||||
# but there is *no need* to - this query is run seldom and is cached.
|
||||
|
||||
|
||||
$params = array();
|
||||
$params['status'] = "Available|Temporarily unavailable|Archived"; # we want them all
|
||||
$params['limit'] = "10000000"; # no limit
|
||||
|
||||
|
||||
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, $params);
|
||||
$internal_request->skip_limits = true;
|
||||
$response = OkapiServiceRunner::call("services/caches/search/all", $internal_request);
|
||||
$cache_codes = $response['results'];
|
||||
|
||||
|
||||
$internal_request = new OkapiInternalRequest(new OkapiInternalConsumer(), null, array(
|
||||
'cache_codes' => implode('|', $cache_codes),
|
||||
'fields' => 'internal_id|code|name|location|type|status|rating|recommendations|founds|trackables_count'
|
||||
));
|
||||
$internal_request->skip_limits = true;
|
||||
$caches = OkapiServiceRunner::call("services/caches/geocaches", $internal_request);
|
||||
|
||||
|
||||
foreach ($caches as $cache)
|
||||
{
|
||||
$row = self::generate_short_row($cache);
|
||||
@ -171,18 +171,18 @@ class TileTree
|
||||
else
|
||||
{
|
||||
# We will use the parent tile to compute the contents of this tile.
|
||||
|
||||
|
||||
$parent_zoom = $zoom - 1;
|
||||
$parent_x = $x >> 1;
|
||||
$parent_y = $y >> 1;
|
||||
|
||||
|
||||
$status = self::get_tile_status($parent_zoom, $parent_x, $parent_y);
|
||||
if ($status === null) # Not computed.
|
||||
{
|
||||
$time_started = microtime(true);
|
||||
$status = self::compute_tile($parent_zoom, $parent_x, $parent_y);
|
||||
}
|
||||
|
||||
|
||||
if ($status === 1) # Computed and empty.
|
||||
{
|
||||
# No need to check.
|
||||
@ -197,11 +197,11 @@ class TileTree
|
||||
$right_z21x = ((($parent_x + 1) << 1) << $scale) + $margin;
|
||||
$top_z21y = (($parent_y << 1) << $scale) - $margin;
|
||||
$bottom_z21y = ((($parent_y + 1) << 1) << $scale) + $margin;
|
||||
|
||||
|
||||
# Choose the right quarter.
|
||||
# |1 2|
|
||||
# |3 4|
|
||||
|
||||
|
||||
if ($x & 1) # 2 or 4
|
||||
$left_z21x = $parentcenter_z21x - $margin;
|
||||
else # 1 or 3
|
||||
@ -210,9 +210,9 @@ class TileTree
|
||||
$top_z21y = $parentcenter_z21y - $margin;
|
||||
else # 1 or 2
|
||||
$bottom_z21y = $parentcenter_z21y + $margin;
|
||||
|
||||
|
||||
# Cache the result.
|
||||
|
||||
|
||||
Db::execute("
|
||||
replace into okapi_tile_caches (
|
||||
z, x, y, cache_id, z21x, z21y, status, type, rating, flags
|
||||
@ -245,9 +245,9 @@ class TileTree
|
||||
$status = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Mark tile as computed.
|
||||
|
||||
|
||||
Db::execute("
|
||||
replace into okapi_tile_status (z, x, y, status)
|
||||
values (
|
||||
@ -257,10 +257,10 @@ class TileTree
|
||||
'".mysql_real_escape_string($status)."'
|
||||
);
|
||||
");
|
||||
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert OKAPI's cache object to a short database row to be inserted
|
||||
* into okapi_tile_caches table. Returns the list of the following attributes:
|
||||
@ -280,7 +280,7 @@ class TileTree
|
||||
return array($cache['internal_id'], $z21x, $z21y, Okapi::cache_status_name2id($cache['status']),
|
||||
Okapi::cache_type_name2id($cache['type']), $cache['rating'], $flags);
|
||||
}
|
||||
|
||||
|
||||
private static function latlon_to_z21xy($lat, $lon)
|
||||
{
|
||||
$offset = 128 << 21;
|
||||
|
@ -22,22 +22,22 @@ class WebService
|
||||
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')))
|
||||
@ -58,9 +58,9 @@ class WebService
|
||||
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')))
|
||||
|
@ -3,7 +3,7 @@
|
||||
<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.
|
||||
<b>ignored</b>.
|
||||
Read the docs on separate parameters for details.</p>
|
||||
</desc>
|
||||
<req name='cache_code'>
|
||||
|
@ -26,7 +26,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$search_params = SearchAssistant::get_common_search_params($request);
|
||||
|
@ -18,7 +18,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# You may wonder, why there are no parameters like "bbox" or "center" in the
|
||||
@ -27,7 +27,7 @@ class WebService
|
||||
# make the documentation very fuzzy. That's why they were intentionally
|
||||
# left out of the "search/all" method, and put in separate (individual) ones.
|
||||
# It's much easier to grasp their meaning this way.
|
||||
|
||||
|
||||
$tmp = $request->get_parameter('bbox');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('bbox');
|
||||
@ -49,9 +49,9 @@ class WebService
|
||||
throw new InvalidParam('bbox', "Latitudes have to be within -90..90 range.");
|
||||
if ($bbeast > 180 || $bbeast < -180 || $bbwest > 180 || $bbwest < -180)
|
||||
throw new InvalidParam('bbox', "Longitudes have to be within -180..180 range.");
|
||||
|
||||
|
||||
# Construct SQL conditions for the specified bounding box.
|
||||
|
||||
|
||||
$where_conds = array();
|
||||
$where_conds[] = "caches.latitude between '".mysql_real_escape_string($bbsouth)."' and '".mysql_real_escape_string($bbnorth)."'";
|
||||
if ($bbeast > $bbwest)
|
||||
@ -65,23 +65,23 @@ class WebService
|
||||
# For example, $bbwest = 179 and $bbeast = -179.
|
||||
$where_conds[] = "(caches.longitude > '".mysql_real_escape_string($bbwest)."' or caches.longitude < '".mysql_real_escape_string($bbeast)."')";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# In the method description, we promised to return caches ordered by the *rough*
|
||||
# distance from the center of the bounding box. We'll use ORDER BY with a simplified
|
||||
# distance formula and combine it with the LIMIT clause to get the best results.
|
||||
#
|
||||
|
||||
|
||||
$center_lat = ($bbsouth + $bbnorth) / 2.0;
|
||||
$center_lon = ($bbwest + $bbeast) / 2.0;
|
||||
|
||||
$center_lon = ($bbwest + $bbeast) / 2.0;
|
||||
|
||||
$search_params = SearchAssistant::get_common_search_params($request);
|
||||
$search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
|
||||
$search_params['order_by'][] = Okapi::get_distance_sql($center_lat, $center_lon,
|
||||
"caches.latitude", "caches.longitude"); # not replaced; added to the end!
|
||||
|
||||
|
||||
$result = SearchAssistant::get_common_search_result($search_params);
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns one of: array('cache_code', 'OPXXXX'), array('internal_id', '12345'),
|
||||
* array('uuid', 'A408C3...') or null.
|
||||
@ -27,7 +27,7 @@ class WebService
|
||||
private static function get_cache_key($url)
|
||||
{
|
||||
# Determine our own domain.
|
||||
|
||||
|
||||
static $host = null;
|
||||
static $length = null;
|
||||
if ($host == null)
|
||||
@ -37,9 +37,9 @@ class WebService
|
||||
$host = substr($host, 4);
|
||||
$length = strlen($host);
|
||||
}
|
||||
|
||||
|
||||
# Parse the URL
|
||||
|
||||
|
||||
$uri = parse_url($url);
|
||||
if ($uri == false)
|
||||
return null;
|
||||
@ -75,11 +75,11 @@ class WebService
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Retrieve the list of URLs to check.
|
||||
|
||||
|
||||
$tmp = $request->get_parameter('urls');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('urls');
|
||||
@ -89,9 +89,9 @@ class WebService
|
||||
if (!in_array($as_dict, array('true', 'false')))
|
||||
throw new InvalidParam('as_dict');
|
||||
$as_dict = ($as_dict == 'true');
|
||||
|
||||
|
||||
# Generate the lists of keys.
|
||||
|
||||
|
||||
$results = array();
|
||||
$urls_with = array(
|
||||
'cache_code' => array(),
|
||||
@ -106,14 +106,14 @@ class WebService
|
||||
else
|
||||
$results[$url_ref] = null;
|
||||
}
|
||||
|
||||
|
||||
# Include 'cache_code' references.
|
||||
|
||||
|
||||
foreach ($urls_with['cache_code'] as $url => $cache_code)
|
||||
$results[$url] = $cache_code;
|
||||
|
||||
|
||||
# Include 'internal_id' references.
|
||||
|
||||
|
||||
$internal_ids = array_values($urls_with['internal_id']);
|
||||
if (count($internal_ids) > 0)
|
||||
{
|
||||
@ -135,9 +135,9 @@ class WebService
|
||||
$results[$url] = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Include 'uuid' references.
|
||||
|
||||
|
||||
$uuids = array_values($urls_with['uuid']);
|
||||
if (count($uuids) > 0)
|
||||
{
|
||||
@ -159,9 +159,9 @@ class WebService
|
||||
$results[$url] = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Format the results according to the 'as_dict' parameter.
|
||||
|
||||
|
||||
if ($as_dict)
|
||||
return Okapi::formatted_response($request, $results);
|
||||
else
|
||||
|
@ -18,7 +18,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# You may wonder, why there are no parameters like "bbox" or "center" in the
|
||||
@ -27,7 +27,7 @@ class WebService
|
||||
# make the documentation very fuzzy. That's why they were intentionally
|
||||
# left out of the "search/all" method, and put in separate (individual) ones.
|
||||
# It's much easier to grasp their meaning this way.
|
||||
|
||||
|
||||
$tmp = $request->get_parameter('center');
|
||||
if (!$tmp)
|
||||
throw new ParamMissing('center');
|
||||
@ -45,18 +45,18 @@ class WebService
|
||||
throw new InvalidParam('center', "Latitudes have to be within -90..90 range.");
|
||||
if ($center_lon > 180 || $center_lon < -180)
|
||||
throw new InvalidParam('center', "Longitudes have to be within -180..180 range.");
|
||||
|
||||
|
||||
#
|
||||
# In the method description, we promised to return caches ordered by the *rough*
|
||||
# distance from the center point. We'll use ORDER BY with a simplified distance
|
||||
# formula and combine it with the LIMIT clause to get the best results.
|
||||
#
|
||||
|
||||
|
||||
$distance_formula = Okapi::get_distance_sql($center_lat, $center_lon, "caches.latitude", "caches.longitude");
|
||||
|
||||
|
||||
# 'radius' parameter is optional. If not given, we'll have to calculate the
|
||||
# distance for every cache in the database.
|
||||
|
||||
|
||||
$where_conds = array();
|
||||
$radius = null;
|
||||
if ($tmp = $request->get_parameter('radius'))
|
||||
@ -69,18 +69,18 @@ class WebService
|
||||
$radius *= 1000; # this one is given in kilemeters, converting to meters!
|
||||
$where_conds[] = "$distance_formula <= '".mysql_real_escape_string($radius)."'";
|
||||
}
|
||||
|
||||
|
||||
$search_params = SearchAssistant::get_common_search_params($request);
|
||||
$search_params['where_conds'] = array_merge($where_conds, $search_params['where_conds']);
|
||||
$search_params['order_by'][] = $distance_formula; # not replaced; added to the end!
|
||||
|
||||
|
||||
$result = SearchAssistant::get_common_search_result($search_params);
|
||||
if ($radius == null)
|
||||
{
|
||||
# 'more' is meaningless in this case, we'll remove it.
|
||||
unset($result['more']);
|
||||
unset($result['more']);
|
||||
}
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get [set_id, date_created, expires] for the given params_hash
|
||||
* (or [null, null, null] if not found).
|
||||
@ -43,11 +43,11 @@ class WebService
|
||||
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);
|
||||
@ -60,9 +60,9 @@ class WebService
|
||||
$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'),
|
||||
@ -73,43 +73,43 @@ class WebService
|
||||
$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 (
|
||||
@ -129,13 +129,13 @@ class WebService
|
||||
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)."'
|
||||
@ -150,15 +150,15 @@ class WebService
|
||||
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("
|
||||
@ -167,7 +167,7 @@ class WebService
|
||||
where id = '".mysql_real_escape_string($set_id)."'
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
return array(
|
||||
'set_id' => "$set_id",
|
||||
'generated_at' => date('c', $date_created),
|
||||
|
@ -19,7 +19,7 @@ class SearchAssistant
|
||||
* given OKAPI request. Most cache search methods share a common set
|
||||
* of filtering parameters recognized by this method. It returns
|
||||
* a dictionary of the following structure:
|
||||
*
|
||||
*
|
||||
* - "where_conds" - list of additional WHERE conditions to be ANDed
|
||||
* to the rest of your SQL query,
|
||||
* - "offset" - value of the offset parameter to be used in the LIMIT clause,
|
||||
@ -32,16 +32,16 @@ class SearchAssistant
|
||||
{
|
||||
$where_conds = array('true');
|
||||
$extra_tables = array();
|
||||
|
||||
|
||||
# At the beginning we have to set up some "magic e$Xpressions".
|
||||
# We will use them to make our query run on both OCPL and OCDE databases.
|
||||
|
||||
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
{
|
||||
# OCPL's 'caches' table contains some fields which OCDE's does not
|
||||
# (topratings, founds, notfounds, last_found, votes, score). If
|
||||
# we're being run on OCPL installation, we will simply use them.
|
||||
|
||||
|
||||
$X_TOPRATINGS = 'caches.topratings';
|
||||
$X_FOUNDS = 'caches.founds';
|
||||
$X_NOTFOUNDS = 'caches.notfounds';
|
||||
@ -57,22 +57,22 @@ class SearchAssistant
|
||||
# additional table in our query (along with a proper WHERE
|
||||
# condition) and we will map the field expressions to
|
||||
# approriate places.
|
||||
|
||||
|
||||
$extra_tables[] = 'stat_caches';
|
||||
$where_conds[] = 'stat_caches.cache_id = caches.cache_id';
|
||||
|
||||
|
||||
$X_TOPRATINGS = 'stat_caches.toprating';
|
||||
$X_FOUNDS = 'stat_caches.found';
|
||||
$X_NOTFOUNDS = 'stat_caches.notfound';
|
||||
$X_LAST_FOUND = 'stat_caches.last_found';
|
||||
$X_VOTES = '0'; // no support for ratings
|
||||
$X_VOTES = '0'; // no support for ratings
|
||||
$X_SCORE = '0'; // no support for ratings
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# type
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('type'))
|
||||
{
|
||||
$operator = "in";
|
||||
@ -96,11 +96,11 @@ class SearchAssistant
|
||||
}
|
||||
$where_conds[] = "caches.type $operator ('".implode("','", array_map('mysql_real_escape_string', $types))."')";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# size2
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('size2'))
|
||||
{
|
||||
$operator = "in";
|
||||
@ -128,7 +128,7 @@ class SearchAssistant
|
||||
#
|
||||
# status - filter by status codes
|
||||
#
|
||||
|
||||
|
||||
$tmp = $request->get_parameter('status');
|
||||
if ($tmp == null) $tmp = "Available";
|
||||
$codes = array();
|
||||
@ -144,11 +144,11 @@ class SearchAssistant
|
||||
}
|
||||
}
|
||||
$where_conds[] = "caches.status in ('".implode("','", array_map('mysql_real_escape_string', $codes))."')";
|
||||
|
||||
|
||||
#
|
||||
# owner_uuid
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('owner_uuid'))
|
||||
{
|
||||
$operator = "in";
|
||||
@ -171,11 +171,11 @@ class SearchAssistant
|
||||
$user_ids[] = $user['internal_id'];
|
||||
$where_conds[] = "caches.user_id $operator ('".implode("','", array_map('mysql_real_escape_string', $user_ids))."')";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# terrain, difficulty, size, rating - these are similar, we'll do them in a loop
|
||||
#
|
||||
|
||||
|
||||
foreach (array('terrain', 'difficulty', 'size', 'rating') as $param_name)
|
||||
{
|
||||
if ($tmp = $request->get_parameter($param_name))
|
||||
@ -247,11 +247,11 @@ class SearchAssistant
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# min_rcmds
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('min_rcmds'))
|
||||
{
|
||||
if ($tmp[strlen($tmp) - 1] == '%')
|
||||
@ -270,33 +270,33 @@ class SearchAssistant
|
||||
throw new InvalidParam('min_rcmds', "'$tmp'");
|
||||
$where_conds[] = "$X_TOPRATINGS >= '".mysql_real_escape_string($tmp)."'";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# min_founds
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('min_founds'))
|
||||
{
|
||||
if (!is_numeric($tmp))
|
||||
throw new InvalidParam('min_founds', "'$tmp'");
|
||||
$where_conds[] = "$X_FOUNDS >= '".mysql_real_escape_string($tmp)."'";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# max_founds
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('max_founds'))
|
||||
{
|
||||
if (!is_numeric($tmp))
|
||||
throw new InvalidParam('max_founds', "'$tmp'");
|
||||
$where_conds[] = "$X_FOUNDS <= '".mysql_real_escape_string($tmp)."'";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# modified_since
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('modified_since'))
|
||||
{
|
||||
$timestamp = strtotime($tmp);
|
||||
@ -305,11 +305,11 @@ class SearchAssistant
|
||||
else
|
||||
throw new InvalidParam('modified_since', "'$tmp' is not in a valid format or is not a valid date.");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# found_status
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('found_status'))
|
||||
{
|
||||
if ($request->token == null)
|
||||
@ -323,11 +323,11 @@ class SearchAssistant
|
||||
$where_conds[] = "caches.cache_id $operator ('".implode("','", array_map('mysql_real_escape_string', $found_cache_ids))."')";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# found_by
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('found_by'))
|
||||
{
|
||||
try {
|
||||
@ -339,11 +339,11 @@ class SearchAssistant
|
||||
$found_cache_ids = self::get_found_cache_ids($user['internal_id']);
|
||||
$where_conds[] = "caches.cache_id in ('".implode("','", array_map('mysql_real_escape_string', $found_cache_ids))."')";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# not_found_by
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('not_found_by'))
|
||||
{
|
||||
try {
|
||||
@ -355,11 +355,11 @@ class SearchAssistant
|
||||
$found_cache_ids = self::get_found_cache_ids($user['internal_id']);
|
||||
$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)
|
||||
@ -380,7 +380,7 @@ class SearchAssistant
|
||||
#
|
||||
# exclude_ignored
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('exclude_ignored'))
|
||||
{
|
||||
if ($request->token == null)
|
||||
@ -396,11 +396,11 @@ class SearchAssistant
|
||||
$where_conds[] = "cache_id not in ('".implode("','", array_map('mysql_real_escape_string', $ignored_cache_ids))."')";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# exclude_my_own
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('exclude_my_own'))
|
||||
{
|
||||
if ($request->token == null)
|
||||
@ -410,26 +410,26 @@ class SearchAssistant
|
||||
if ($tmp == 'true')
|
||||
$where_conds[] = "caches.user_id != '".mysql_real_escape_string($request->token->user_id)."'";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# name
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('name'))
|
||||
{
|
||||
# WRTODO: Make this more user-friendly. See:
|
||||
# http://code.google.com/p/opencaching-api/issues/detail?id=121
|
||||
|
||||
|
||||
if (strlen($tmp) > 100)
|
||||
throw new InvalidParam('name', "Maximum length of 'name' parameter is 100 characters");
|
||||
$tmp = str_replace("*", "%", str_replace("%", "%%", $tmp));
|
||||
$tmp = str_replace("*", "%", str_replace("%", "%%", $tmp));
|
||||
$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))
|
||||
@ -444,11 +444,11 @@ class SearchAssistant
|
||||
";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# ftf_hunter
|
||||
#
|
||||
|
||||
|
||||
if ($tmp = $request->get_parameter('ftf_hunter'))
|
||||
{
|
||||
if (!in_array($tmp, array('true', 'false'), 1))
|
||||
@ -458,15 +458,15 @@ class SearchAssistant
|
||||
$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
|
||||
@ -478,22 +478,22 @@ class SearchAssistant
|
||||
$where_conds[] = "osr_and.cache_id = caches.cache_id";
|
||||
$where_conds[] = "osr_and.set_id = '".mysql_real_escape_string($tmp)."'";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# limit
|
||||
#
|
||||
|
||||
|
||||
$limit = $request->get_parameter('limit');
|
||||
if ($limit == null) $limit = "100";
|
||||
if (!is_numeric($limit))
|
||||
throw new InvalidParam('limit', "'$limit'");
|
||||
if ($limit < 1 || (($limit > 500) && (!$request->skip_limits)))
|
||||
throw new InvalidParam('limit', "Has to be between 1 and 500.");
|
||||
|
||||
|
||||
#
|
||||
# offset
|
||||
#
|
||||
|
||||
|
||||
$offset = $request->get_parameter('offset');
|
||||
if ($offset == null) $offset = "0";
|
||||
if (!is_numeric($offset))
|
||||
@ -502,17 +502,17 @@ class SearchAssistant
|
||||
throw new BadRequest("The sum of offset and limit may not exceed 500.");
|
||||
if ($offset < 0 || $offset > 499)
|
||||
throw new InvalidParam('offset', "Has to be between 0 and 499.");
|
||||
|
||||
|
||||
#
|
||||
# order_by
|
||||
#
|
||||
|
||||
|
||||
$order_clauses = array();
|
||||
$order_by = $request->get_parameter('order_by');
|
||||
if ($order_by != null)
|
||||
{
|
||||
$order_by = explode('|', $order_by);
|
||||
foreach ($order_by as $field)
|
||||
foreach ($order_by as $field)
|
||||
{
|
||||
$dir = 'asc';
|
||||
if ($field[0] == '-')
|
||||
@ -537,15 +537,15 @@ class SearchAssistant
|
||||
$order_clauses[] = "($cl) $dir";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# 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,
|
||||
@ -556,13 +556,13 @@ class SearchAssistant
|
||||
|
||||
return $ret_array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search for caches using given conditions and options. Return
|
||||
* an array in a "standard" format of array('results' => list of
|
||||
* cache codes, 'more' => boolean). This method takes care of the
|
||||
* 'more' variable in an appropriate way.
|
||||
*
|
||||
*
|
||||
* The $options parameter include:
|
||||
* - where_conds - list of additional WHERE conditions to be ANDed
|
||||
* to the rest of your SQL query,
|
||||
@ -581,10 +581,10 @@ class SearchAssistant
|
||||
array('caches.wp_oc is not null'),
|
||||
$options['where_conds']
|
||||
);
|
||||
|
||||
|
||||
# We need to pull limit+1 items, in order to properly determine the
|
||||
# value of "more" variable.
|
||||
|
||||
|
||||
$cache_codes = Db::select_column("
|
||||
select caches.wp_oc
|
||||
from ".implode(", ", $tables)."
|
||||
@ -592,7 +592,7 @@ class SearchAssistant
|
||||
".((count($options['order_by']) > 0) ? "order by ".implode(", ", $options['order_by']) : "")."
|
||||
limit ".($options['offset']).", ".($options['limit'] + 1).";
|
||||
");
|
||||
|
||||
|
||||
if (count($cache_codes) > $options['limit'])
|
||||
{
|
||||
$more = true;
|
||||
@ -600,16 +600,16 @@ class SearchAssistant
|
||||
} else {
|
||||
$more = false;
|
||||
}
|
||||
|
||||
|
||||
$result = array(
|
||||
'results' => $cache_codes,
|
||||
'more' => $more,
|
||||
);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of cache IDs which were found by given user.
|
||||
|
||||
/**
|
||||
* Get the list of cache IDs which were found by given user.
|
||||
* Parameter needs to be *internal* user id, not uuid.
|
||||
*/
|
||||
private static function get_found_cache_ids($internal_user_id)
|
||||
|
@ -9,6 +9,7 @@ use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiRequest;
|
||||
use okapi\ParamMissing;
|
||||
use okapi\InvalidParam;
|
||||
use okapi\BadRequest;
|
||||
|
||||
class WebService
|
||||
{
|
||||
@ -18,7 +19,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# Check search method
|
||||
@ -35,7 +36,7 @@ class WebService
|
||||
$search_params = json_decode($search_params, true);
|
||||
if (!is_array($search_params))
|
||||
throw new InvalidParam('search_params', "Should be a JSON-encoded dictionary");
|
||||
|
||||
|
||||
# Check retrieval method
|
||||
$retr_method = $request->get_parameter('retr_method');
|
||||
if (!$retr_method)
|
||||
@ -48,14 +49,17 @@ class WebService
|
||||
$retr_params = json_decode($retr_params, true);
|
||||
if (!is_array($retr_params))
|
||||
throw new InvalidParam('retr_params', "Should be a JSON-encoded dictionary");
|
||||
|
||||
|
||||
self::map_values_to_strings($search_params);
|
||||
self::map_values_to_strings($retr_params);
|
||||
|
||||
# Wrapped?
|
||||
$wrap = $request->get_parameter('wrap');
|
||||
if ($wrap == null) throw new ParamMissing('wrap');
|
||||
if (!in_array($wrap, array('true', 'false')))
|
||||
throw new InvalidParam('wrap');
|
||||
$wrap = ($wrap == 'true');
|
||||
|
||||
|
||||
# Run search method
|
||||
try
|
||||
{
|
||||
@ -67,7 +71,7 @@ class WebService
|
||||
throw new InvalidParam('search_params', "Search method responded with the ".
|
||||
"following error message: ".$e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
# Run retrieval method
|
||||
try
|
||||
{
|
||||
@ -80,7 +84,7 @@ class WebService
|
||||
throw new InvalidParam('retr_params', "Retrieval method responded with the ".
|
||||
"following error message: ".$e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
if ($wrap)
|
||||
{
|
||||
# $retr_result might be a PHP object, but also might be a binary response
|
||||
@ -102,4 +106,16 @@ class WebService
|
||||
return Okapi::formatted_response($request, $retr_result);
|
||||
}
|
||||
}
|
||||
|
||||
private static function map_values_to_strings(&$dict)
|
||||
{
|
||||
foreach (array_keys($dict) as $key)
|
||||
{
|
||||
$val = $dict[$key];
|
||||
if (is_numeric($val) || is_string($val))
|
||||
$dict[$key] = (string)$val;
|
||||
else
|
||||
throw new BadRequest("Invalid value format for key: ".$key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,10 +21,10 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static $valid_field_names = array(
|
||||
'uuid', 'cache_code', 'date', 'user', 'type', 'was_recommended', 'comment',
|
||||
'internal_id',
|
||||
'images', 'internal_id',
|
||||
);
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
@ -37,7 +37,7 @@ class WebService
|
||||
}
|
||||
else
|
||||
$log_uuids = explode("|", $log_uuids);
|
||||
|
||||
|
||||
if ((count($log_uuids) > 500) && (!$request->skip_limits))
|
||||
throw new InvalidParam('log_uuids', "Maximum allowed number of referenced ".
|
||||
"log entries is 500. You provided ".count($log_uuids)." UUIDs.");
|
||||
@ -49,7 +49,7 @@ class WebService
|
||||
foreach ($fields as $field)
|
||||
if (!in_array($field, self::$valid_field_names))
|
||||
throw new InvalidParam('fields', "'$field' is not a valid field code.");
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select
|
||||
cl.id, c.wp_oc as cache_code, cl.uuid, cl.type,
|
||||
@ -71,6 +71,7 @@ class WebService
|
||||
and c.status in (1,2,3)
|
||||
");
|
||||
$results = array();
|
||||
$log_id2uuid = array(); /* Maps logs' internal_ids to uuids */
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$results[$row['uuid']] = array(
|
||||
@ -85,30 +86,60 @@ class WebService
|
||||
'type' => Okapi::logtypeid2name($row['type']),
|
||||
'was_recommended' => $row['was_recommended'] ? true : false,
|
||||
'comment' => $row['text'],
|
||||
'images' => array(),
|
||||
'internal_id' => $row['id'],
|
||||
);
|
||||
$log_id2uuid[$row['id']] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
|
||||
# fetch images
|
||||
|
||||
if (in_array('images', $fields))
|
||||
{
|
||||
$rs = Db::query("
|
||||
select object_id, uuid, url, title, spoiler
|
||||
from pictures
|
||||
where
|
||||
object_type = 1
|
||||
and object_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($log_id2uuid)))."')
|
||||
and display = 1 /* currently is always 1 for logpix */
|
||||
and unknown_format = 0
|
||||
order by date_created
|
||||
");
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$results[$log_id2uuid[$row['object_id']]]['images'][] =
|
||||
array(
|
||||
'uuid' => $row['uuid'],
|
||||
'url' => $row['url'],
|
||||
'thumb_url' => Settings::get('SITE_URL') . 'thumbs.php?uuid=' . $row['uuid'],
|
||||
'caption' => $row['title'],
|
||||
'is_spoiler' => ($row['spoiler'] ? true : false),
|
||||
);
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
}
|
||||
|
||||
# Check which UUIDs were not found and mark them with null.
|
||||
|
||||
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
if (!isset($results[$log_uuid]))
|
||||
$results[$log_uuid] = null;
|
||||
|
||||
|
||||
# Remove unwanted fields.
|
||||
|
||||
|
||||
foreach (self::$valid_field_names as $field)
|
||||
if (!in_array($field, $fields))
|
||||
foreach ($results as &$result_ref)
|
||||
unset($result_ref[$field]);
|
||||
|
||||
|
||||
# Order the results in the same order as the input codes were given.
|
||||
|
||||
|
||||
$ordered_results = array();
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
$ordered_results[$log_uuid] = $results[$log_uuid];
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $ordered_results);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class WebService
|
||||
if (!$log_uuid) throw new ParamMissing('log_uuid');
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "date|user|type|comment";
|
||||
|
||||
|
||||
$results = OkapiServiceRunner::call('services/logs/entries', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('log_uuids' => $log_uuid,
|
||||
'fields' => $fields)));
|
||||
|
@ -40,6 +40,20 @@
|
||||
in this log entry,</p>
|
||||
</li>
|
||||
<li><b>comment</b> - HTML string, text entered with the log entry,</li>
|
||||
<li>
|
||||
<p><b>images</b> - list of dictionaries, each dictionary represents one
|
||||
image saved along with the log; each dictionary has the following
|
||||
structure:</p>
|
||||
<ul>
|
||||
<li><b>uuid</b> - UUID of the image,</li>
|
||||
<li><b>url</b> - URL of the image,</li>
|
||||
<li><b>thumb_url</b> - URL of a small (thumb) version of the image,</li>
|
||||
<li><b>caption</b> - plain-text string, caption of the image,</li>
|
||||
<li><b>is_spoiler</b> - boolean, if <b>true</b> then the image is
|
||||
a spoiler image and should not be displayed to the user unless
|
||||
the user explicitly asks for it.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p><b>internal_id</b> - undocumented, you <u>should not</u> use
|
||||
this unless you really know you need to. Internal IDs are
|
||||
|
@ -27,7 +27,7 @@ class WebService
|
||||
if (!$cache_code) throw new ParamMissing('cache_code');
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields) $fields = "uuid|date|user|type|comment";
|
||||
|
||||
|
||||
$offset = $request->get_parameter('offset');
|
||||
if (!$offset) $offset = "0";
|
||||
if ((((int)$offset) != $offset) || ((int)$offset) < 0)
|
||||
@ -37,15 +37,15 @@ class WebService
|
||||
if ($limit == "none") $limit = "999999999";
|
||||
if ((((int)$limit) != $limit) || ((int)$limit) < 0)
|
||||
throw new InvalidParam('limit', "Expecting non-negative integer or 'none'.");
|
||||
|
||||
|
||||
# Check if code exists and retrieve cache ID (this will throw
|
||||
# a proper exception on invalid code).
|
||||
|
||||
|
||||
$cache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('cache_code' => $cache_code, 'fields' => 'internal_id')));
|
||||
|
||||
|
||||
# Cache exists. Getting the uuids of its logs.
|
||||
|
||||
|
||||
$log_uuids = Db::select_column("
|
||||
select uuid
|
||||
from cache_logs
|
||||
@ -55,9 +55,9 @@ class WebService
|
||||
order by date desc
|
||||
limit $offset, $limit
|
||||
");
|
||||
|
||||
|
||||
# Getting the logs themselves. Formatting as an ordered list.
|
||||
|
||||
|
||||
$internal_request = new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('log_uuids' => implode("|", $log_uuids),
|
||||
'fields' => $fields));
|
||||
@ -66,7 +66,7 @@ class WebService
|
||||
$results = array();
|
||||
foreach ($log_uuids as $log_uuid)
|
||||
$results[] = $logs[$log_uuid];
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use okapi\services\caches\search\SearchAssistant;
|
||||
use okapi\BadRequest;
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* This exception is thrown by WebService::_call method, when error is detected in
|
||||
* user-supplied data. It is not a BadRequest exception - it does not imply that
|
||||
* the Consumer did anything wrong (it's the user who did). This exception shouldn't
|
||||
@ -31,9 +31,9 @@ class WebService
|
||||
return array(
|
||||
'min_auth_level' => 3
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a new log entry and return log entry uuid. Throws
|
||||
* CannotPublishException or BadRequest on errors.
|
||||
*/
|
||||
@ -43,15 +43,23 @@ class WebService
|
||||
# CannotPublishException and standard BadRequest/InvalidParam exceptions!
|
||||
# Notice, that this is "_call" method, not the usual "call" (see below
|
||||
# for "call").
|
||||
|
||||
|
||||
$cache_code = $request->get_parameter('cache_code');
|
||||
if (!$cache_code) throw new ParamMissing('cache_code');
|
||||
|
||||
$logtype = $request->get_parameter('logtype');
|
||||
if (!$logtype) throw new ParamMissing('logtype');
|
||||
if (!in_array($logtype, array('Found it', "Didn't find it", 'Comment')))
|
||||
throw new InvalidParam('logtype', "'$logtype' in not a valid logtype code.");
|
||||
|
||||
$comment = $request->get_parameter('comment');
|
||||
if (!$comment) $comment = "";
|
||||
|
||||
$comment_format = $request->get_parameter('comment_format');
|
||||
if (!$comment_format) $comment_format = "auto";
|
||||
if (!in_array($comment_format, array('auto', 'html', 'plaintext')))
|
||||
throw new InvalidParam('comment_format', $comment_format);
|
||||
|
||||
$tmp = $request->get_parameter('when');
|
||||
if ($tmp)
|
||||
{
|
||||
@ -64,10 +72,12 @@ class WebService
|
||||
}
|
||||
else
|
||||
$when = time();
|
||||
|
||||
$on_duplicate = $request->get_parameter('on_duplicate');
|
||||
if (!$on_duplicate) $on_duplicate = "silent_success";
|
||||
if (!in_array($on_duplicate, array('silent_success', 'user_error', 'continue')))
|
||||
throw new InvalidParam('on_duplicate', "Unknown option: '$on_duplicate'.");
|
||||
|
||||
$rating = $request->get_parameter('rating');
|
||||
if ($rating !== null && (!in_array($rating, array(1,2,3,4,5))))
|
||||
throw new InvalidParam('rating', "If present, it must be an integer in the 1..5 scale.");
|
||||
@ -78,11 +88,12 @@ class WebService
|
||||
# We will remove the rating request and change the success message
|
||||
# (which will be returned IF the rest of the query will meet all the
|
||||
# requirements).
|
||||
|
||||
|
||||
self::$success_message .= " ".sprintf(_("However, your cache rating was ignored, because %s does not have a rating system."),
|
||||
Okapi::get_normalized_site_name());
|
||||
$rating = null;
|
||||
}
|
||||
|
||||
$recommend = $request->get_parameter('recommend');
|
||||
if (!$recommend) $recommend = 'false';
|
||||
if (!in_array($recommend, array('true', 'false')))
|
||||
@ -90,6 +101,7 @@ class WebService
|
||||
$recommend = ($recommend == 'true');
|
||||
if ($recommend && $logtype != 'Found it')
|
||||
throw new BadRequest(_("Recommending is allowed only for 'Found it' logtypes."));
|
||||
|
||||
$needs_maintenance = $request->get_parameter('needs_maintenance');
|
||||
if (!$needs_maintenance) $needs_maintenance = 'false';
|
||||
if (!in_array($needs_maintenance, array('true', 'false')))
|
||||
@ -102,26 +114,26 @@ class WebService
|
||||
Okapi::get_normalized_site_name());
|
||||
$needs_maintenance = false;
|
||||
}
|
||||
|
||||
|
||||
# Check if cache exists and retrieve cache internal ID (this will throw
|
||||
# a proper exception on invalid cache_code). Also, get the user object.
|
||||
|
||||
|
||||
$cache = OkapiServiceRunner::call('services/caches/geocache', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('cache_code' => $cache_code,
|
||||
'fields' => 'internal_id|status|owner|type|req_passwd')));
|
||||
$user = OkapiServiceRunner::call('services/users/by_internal_id', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('internal_id' => $request->token->user_id,
|
||||
'fields' => 'is_admin|uuid|internal_id|caches_found|rcmds_given')));
|
||||
|
||||
|
||||
# Various integrity checks.
|
||||
|
||||
|
||||
if ($cache['type'] == 'Event' && $logtype != 'Comment')
|
||||
throw new CannotPublishException(_('This cache is an Event cache. You cannot "Find it"! (But - you may "Comment" on it.)'));
|
||||
if ($logtype == 'Comment' && strlen(trim($comment)) == 0)
|
||||
throw new CannotPublishException(_("Your have to supply some text for your comment."));
|
||||
|
||||
|
||||
# Password check.
|
||||
|
||||
|
||||
if ($logtype == 'Found it' && $cache['req_passwd'])
|
||||
{
|
||||
$valid_password = Db::select_value("
|
||||
@ -135,24 +147,90 @@ class WebService
|
||||
if (strtolower($supplied_password) != strtolower($valid_password))
|
||||
throw new CannotPublishException(_("Invalid password!"));
|
||||
}
|
||||
|
||||
# Very weird part (as usual). OC stores HTML-lized comments in the database
|
||||
# (it doesn't really matter if 'text_html' field is set to FALSE). OKAPI must
|
||||
# save it in HTML either way. However, escaping plain-text doesn't work.
|
||||
# If we put "<b>" in, it still gets converted to "<b>" before display!
|
||||
# NONE of this process is documented. There doesn't seem to be ANY way to force
|
||||
# OCPL to treat a string as either plain-text nor HTML. It's always something
|
||||
# in between! In other words, we cannot guarantee how it gets displayed in
|
||||
# the end. Since text_html=0 doesn't add <br/>s on its own, we can only add
|
||||
# proper <br/>s and hope it's okay. We will remove the original $comment
|
||||
# variable from our namespace and act on the "pseudoencoded" one.
|
||||
|
||||
$PSEUDOENCODED_comment = htmlspecialchars($comment, ENT_QUOTES);
|
||||
$PSEUDOENCODED_comment = nl2br($PSEUDOENCODED_comment);
|
||||
|
||||
# Prepare our comment to be inserted into the database. This may require
|
||||
# some reformatting which depends on the current OC installation.
|
||||
|
||||
if (Settings::get('OC_BRANCH') == 'oc.de')
|
||||
{
|
||||
# OCDE stores all comments in HTML format, while the 'text_html' field
|
||||
# indicates their *original* format as delivered by the user. This
|
||||
# allows processing the 'text' field contents without caring about the
|
||||
# original format, while still being able to re-create the comment in
|
||||
# its original form. It requires us to HTML-encode plaintext comments
|
||||
# and to indicate this by setting 'html_text' to FALSE.
|
||||
#
|
||||
# For user-supplied HTML comments, OCDE requires us to do additional
|
||||
# HTML purification prior to the insertion into the database.
|
||||
|
||||
if ($comment_format == 'plaintext')
|
||||
{
|
||||
# If we would like to be compatible with old OCDE/OC.nl installation,
|
||||
# "$comment_format == 'auto'" should go here, too. But we must choose
|
||||
# to resemble either old OCDE or OCPL behaviour and opt for OCPL compatibility.
|
||||
|
||||
$formatted_comment = htmlspecialchars($comment, ENT_QUOTES);
|
||||
$formatted_comment = nl2br($formatted_comment);
|
||||
$value_for_text_html_field = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($comment_format == 'auto')
|
||||
{
|
||||
# This does not make sense on HTML comments, but it resembles the
|
||||
# OCPL implementation and is needed for full compatibility with existing
|
||||
# OKAPI clients.
|
||||
|
||||
$formatted_comment = nl2br($comment);
|
||||
}
|
||||
else
|
||||
$formatted_comment = $comment;
|
||||
|
||||
# NOTICE: We are including EXTERNAL OCDE library here! This
|
||||
# code does not belong to OKAPI!
|
||||
|
||||
require_once $GLOBALS['rootpath'] . '../lib/htmlpurifier-4.2.0/library/HTMLPurifier.auto.php';
|
||||
$purifier = new \HTMLPurifier();
|
||||
$formatted_comment = $purifier->purify($formatted_comment);
|
||||
$value_for_text_html_field = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# OCPL is even weirder. It also stores HTML-lized comments in the database
|
||||
# (it doesn't really matter if 'text_html' field is set to FALSE). OKAPI must
|
||||
# save it in HTML either way. However, escaping plain-text doesn't work!
|
||||
# If we put "<b>" in, it still gets converted to "<b>" before display!
|
||||
# NONE of this process is documented within OCPL code. OKAPI uses a dirty
|
||||
# "hack" to save PLAINTEXT comments (let us hope the hack will remain valid).
|
||||
#
|
||||
# OCPL doesn't require HTML purification prior to the database insertion.
|
||||
# HTML seems to be purified dynamically, before it is displayed.
|
||||
|
||||
if ($comment_format == 'plaintext')
|
||||
{
|
||||
$formatted_comment = htmlspecialchars($comment, ENT_QUOTES);
|
||||
$formatted_comment = nl2br($formatted_comment);
|
||||
$formatted_comment = str_replace("&", "&#38;", $formatted_comment);
|
||||
$formatted_comment = str_replace("<", "&#60;", $formatted_comment);
|
||||
$formatted_comment = str_replace(">", "&#62;", $formatted_comment);
|
||||
$value_for_text_html_field = 0; // WRTODO: get rid of
|
||||
}
|
||||
elseif ($comment_format == 'auto')
|
||||
{
|
||||
$formatted_comment = nl2br($comment);
|
||||
$value_for_text_html_field = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$formatted_comment = $comment;
|
||||
$value_for_text_html_field = 1;
|
||||
}
|
||||
}
|
||||
unset($comment);
|
||||
|
||||
|
||||
# Duplicate detection.
|
||||
|
||||
|
||||
if ($on_duplicate != 'continue')
|
||||
{
|
||||
# Attempt to find a log entry made by the same user, for the same cache, with
|
||||
@ -161,7 +239,7 @@ class WebService
|
||||
# DO NOT guarantee that duplicate detection will succeed. If it doesn't,
|
||||
# nothing bad happens (user will just post two similar log entries).
|
||||
# Keep this simple!
|
||||
|
||||
|
||||
$duplicate_uuid = Db::select_value("
|
||||
select uuid
|
||||
from cache_logs
|
||||
@ -170,7 +248,7 @@ class WebService
|
||||
and cache_id = '".mysql_real_escape_string($cache['internal_id'])."'
|
||||
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)."'
|
||||
and text = '".mysql_real_escape_string($formatted_comment)."'
|
||||
".((Settings::get('OC_BRANCH') == 'oc.pl') ? "and deleted = 0" : "")."
|
||||
limit 1
|
||||
");
|
||||
@ -187,9 +265,9 @@ class WebService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Check if already found it (and make sure the user is not the owner).
|
||||
|
||||
|
||||
if (($logtype == 'Found it') || ($logtype == "Didn't find it"))
|
||||
{
|
||||
$has_already_found_it = Db::select_value("
|
||||
@ -206,12 +284,12 @@ class WebService
|
||||
if ($user['uuid'] == $cache['owner']['uuid'])
|
||||
throw new CannotPublishException(_("You are the owner of this cache. You may submit \"Comments\" only!"));
|
||||
}
|
||||
|
||||
|
||||
# Check if the user has already rated the cache. BTW: I don't get this one.
|
||||
# If we already know, that the cache was NOT found yet, then HOW could the
|
||||
# user submit a rating for it? Anyway, I will stick to the procedure
|
||||
# found in log.php. On the bright side, it's fail-safe.
|
||||
|
||||
|
||||
if ($rating)
|
||||
{
|
||||
$has_already_rated = Db::select_value("
|
||||
@ -224,13 +302,13 @@ class WebService
|
||||
if ($has_already_rated)
|
||||
throw new CannotPublishException(_("You have already rated this cache once. Your rating cannot be changed."));
|
||||
}
|
||||
|
||||
|
||||
# If user wants to recommend...
|
||||
|
||||
|
||||
if ($recommend)
|
||||
{
|
||||
# Do the same "fail-safety" check as we did for the rating.
|
||||
|
||||
|
||||
$already_recommended = Db::select_value("
|
||||
select 1
|
||||
from cache_rating
|
||||
@ -240,39 +318,39 @@ class WebService
|
||||
");
|
||||
if ($already_recommended)
|
||||
throw new CannotPublishException(_("You have already recommended this cache once."));
|
||||
|
||||
|
||||
# Check the number of recommendations.
|
||||
|
||||
|
||||
$founds = $user['caches_found'] + 1; // +1, because he'll find THIS ONE in a moment, right?
|
||||
$rcmds_left = floor($founds / 10.0) - $user['rcmds_given'];
|
||||
if ($rcmds_left <= 0)
|
||||
throw new CannotPublishException(_("You don't have any recommendations to give. Find more caches first!"));
|
||||
}
|
||||
|
||||
|
||||
# If user checked the "needs_maintenance" flag, we will shuffle things a little...
|
||||
|
||||
|
||||
if ($needs_maintenance)
|
||||
{
|
||||
# If we're here, then we also know that the "Needs maintenance" log type is supported
|
||||
# by this OC site. However, it's a separate log type, so we might have to submit
|
||||
# two log types together:
|
||||
|
||||
|
||||
if ($logtype == 'Comment')
|
||||
{
|
||||
# If user submits a "Comment", we'll just change its type to "Needs maintenance".
|
||||
# Only one log entry will be issued.
|
||||
|
||||
|
||||
$logtype = 'Needs maintenance';
|
||||
$second_logtype = null;
|
||||
$second_PSEUDOENCODED_comment = null;
|
||||
$second_formatted_comment = null;
|
||||
}
|
||||
elseif ($logtype == 'Found it')
|
||||
{
|
||||
# If "Found it", then we'll issue two log entries: one "Found it" with the
|
||||
# original comment, and second one "Needs maintenance" with empty comment.
|
||||
|
||||
|
||||
$second_logtype = 'Needs maintenance';
|
||||
$second_PSEUDOENCODED_comment = "";
|
||||
$second_formatted_comment = "";
|
||||
}
|
||||
elseif ($logtype == "Didn't find it")
|
||||
{
|
||||
@ -281,10 +359,10 @@ class WebService
|
||||
# will have an empty comment. We will move the comment to the second
|
||||
# "Needs maintenance" log entry. (It's okay for this behavior to change
|
||||
# in the future, but it seems natural to me.)
|
||||
|
||||
|
||||
$second_logtype = 'Needs maintenance';
|
||||
$second_PSEUDOENCODED_comment = $PSEUDOENCODED_comment;
|
||||
$PSEUDOENCODED_comment = "";
|
||||
$second_formatted_comment = $formatted_comment;
|
||||
$formatted_comment = "";
|
||||
}
|
||||
else
|
||||
throw new Exception();
|
||||
@ -293,33 +371,37 @@ class WebService
|
||||
{
|
||||
# User didn't check the "Needs maintenance" flag OR "Needs maintenance" log type
|
||||
# isn't supported by this server.
|
||||
|
||||
|
||||
$second_logtype = null;
|
||||
$second_PSEUDOENCODED_comment = null;
|
||||
$second_formatted_comment = null;
|
||||
}
|
||||
|
||||
|
||||
# Finally! Insert the rows into the log entries table. Update
|
||||
# cache stats and user stats.
|
||||
|
||||
$log_uuid = self::insert_log_row($request->consumer->key, $cache['internal_id'], $user['internal_id'], $logtype, $when, $PSEUDOENCODED_comment);
|
||||
|
||||
$log_uuid = self::insert_log_row(
|
||||
$request->consumer->key, $cache['internal_id'], $user['internal_id'], $logtype,
|
||||
$when, $formatted_comment, $value_for_text_html_field);
|
||||
self::increment_cache_stats($cache['internal_id'], $when, $logtype);
|
||||
self::increment_user_stats($user['internal_id'], $logtype);
|
||||
if ($second_logtype != null)
|
||||
{
|
||||
# Reminder: This will never be called while SUPPORTS_LOGTYPE_NEEDS_MAINTENANCE is off.
|
||||
|
||||
self::insert_log_row($request->consumer->key, $cache['internal_id'], $user['internal_id'], $second_logtype, $when + 1, $second_PSEUDOENCODED_comment);
|
||||
|
||||
self::insert_log_row(
|
||||
$request->consumer->key, $cache['internal_id'], $user['internal_id'], $second_logtype,
|
||||
$when + 1, $second_formatted_comment, $value_for_text_html_field);
|
||||
self::increment_cache_stats($cache['internal_id'], $when + 1, $second_logtype);
|
||||
self::increment_user_stats($user['internal_id'], $second_logtype);
|
||||
}
|
||||
|
||||
|
||||
# Save the rating.
|
||||
|
||||
|
||||
if ($rating)
|
||||
{
|
||||
# This code will be called for OCPL branch only. Earlier, we made sure,
|
||||
# to set $rating to null, if we're running on OCDE.
|
||||
|
||||
|
||||
# OCPL has a little strange way of storing cumulative rating. Instead
|
||||
# of storing the sum of all ratings, OCPL stores the computed average
|
||||
# and update it using multiple floating-point operations. Moreover,
|
||||
@ -329,7 +411,7 @@ class WebService
|
||||
# the rating can never be changed. It surely feels quite inconsistent,
|
||||
# but presumably has some deep logic into it. See also here (Polish):
|
||||
# http://wiki.opencaching.pl/index.php/Oceny_skrzynek
|
||||
|
||||
|
||||
switch ($rating)
|
||||
{
|
||||
case 1: $db_score = -2.0; break;
|
||||
@ -355,47 +437,57 @@ class WebService
|
||||
);
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
# Save recommendation.
|
||||
|
||||
|
||||
if ($recommend)
|
||||
{
|
||||
# Both OCPL and OCDE don't update any stats regarding the number of recommendations
|
||||
# (or - if they do - they do so using triggers). In other words, this is the only
|
||||
# query we have to execute here, regarding the recommendation.
|
||||
|
||||
Db::execute("
|
||||
insert into cache_rating (user_id, cache_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($user['internal_id'])."',
|
||||
'".mysql_real_escape_string($cache['internal_id'])."'
|
||||
);
|
||||
");
|
||||
if (Db::field_exists('cache_rating', 'rating_date'))
|
||||
{
|
||||
Db::execute("
|
||||
insert into cache_rating (user_id, cache_id, rating_date)
|
||||
values (
|
||||
'".mysql_real_escape_string($user['internal_id'])."',
|
||||
'".mysql_real_escape_string($cache['internal_id'])."',
|
||||
from_unixtime('".mysql_real_escape_string($when)."')
|
||||
);
|
||||
");
|
||||
}
|
||||
else
|
||||
{
|
||||
Db::execute("
|
||||
insert into cache_rating (user_id, cache_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($user['internal_id'])."',
|
||||
'".mysql_real_escape_string($cache['internal_id'])."'
|
||||
);
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# 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 = Okapi::get_var_dir().'/images/statpics/statpic'.$user['internal_id'].'.jpg';
|
||||
if (file_exists($filepath))
|
||||
unlink($filepath);
|
||||
|
||||
# Success. Return the uuid.
|
||||
|
||||
|
||||
return $log_uuid;
|
||||
}
|
||||
|
||||
|
||||
private static $success_message = null;
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
# This is the "real" entry point. A wrapper for the _call method.
|
||||
|
||||
|
||||
$langpref = $request->get_parameter('langpref');
|
||||
if (!$langpref) $langpref = "en";
|
||||
|
||||
|
||||
# Error messages thrown via CannotPublishException exceptions should be localized.
|
||||
# They will be delivered for end user to display in his language.
|
||||
|
||||
|
||||
Okapi::gettext_domain_init(explode("|", $langpref));
|
||||
try
|
||||
{
|
||||
@ -421,7 +513,7 @@ class WebService
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
|
||||
|
||||
private static function increment_cache_stats($cache_internal_id, $when, $logtype)
|
||||
{
|
||||
if (Settings::get('OC_BRANCH') == 'oc.de')
|
||||
@ -432,7 +524,7 @@ class WebService
|
||||
else
|
||||
{
|
||||
# OCPL doesn't use triggers for this. We need to update manually.
|
||||
|
||||
|
||||
if ($logtype == 'Found it')
|
||||
{
|
||||
Db::execute("
|
||||
@ -465,7 +557,7 @@ class WebService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function increment_user_stats($user_internal_id, $logtype)
|
||||
{
|
||||
if (Settings::get('OC_BRANCH') == 'oc.de')
|
||||
@ -476,7 +568,7 @@ class WebService
|
||||
else
|
||||
{
|
||||
# OCPL doesn't have triggers for this. We need to update manually.
|
||||
|
||||
|
||||
switch ($logtype)
|
||||
{
|
||||
case 'Found it': $field_to_increment = 'founds_count'; break;
|
||||
@ -493,7 +585,7 @@ class WebService
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function create_uuid()
|
||||
{
|
||||
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
@ -504,29 +596,33 @@ class WebService
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
|
||||
);
|
||||
}
|
||||
|
||||
private static function insert_log_row($consumer_key, $cache_internal_id, $user_internal_id, $logtype, $when, $PSEUDOENCODED_comment)
|
||||
|
||||
private static function insert_log_row(
|
||||
$consumer_key, $cache_internal_id, $user_internal_id, $logtype, $when,
|
||||
$formatted_comment, $text_html
|
||||
)
|
||||
{
|
||||
$log_uuid = self::create_uuid();
|
||||
Db::execute("
|
||||
insert into cache_logs (uuid, cache_id, user_id, type, date, text, last_modified, date_created, node)
|
||||
insert into cache_logs (uuid, cache_id, user_id, type, date, text, text_html, last_modified, date_created, node)
|
||||
values (
|
||||
'".mysql_real_escape_string($log_uuid)."',
|
||||
'".mysql_real_escape_string($cache_internal_id)."',
|
||||
'".mysql_real_escape_string($user_internal_id)."',
|
||||
'".mysql_real_escape_string(Okapi::logtypename2id($logtype))."',
|
||||
from_unixtime('".mysql_real_escape_string($when)."'),
|
||||
'".mysql_real_escape_string($PSEUDOENCODED_comment)."',
|
||||
'".mysql_real_escape_string($formatted_comment)."',
|
||||
'".mysql_real_escape_string($text_html)."',
|
||||
now(),
|
||||
now(),
|
||||
'".mysql_real_escape_string(Settings::get('OC_NODE_ID'))."'
|
||||
);
|
||||
");
|
||||
$log_internal_id = Db::last_insert_id();
|
||||
|
||||
|
||||
# Store additional information on consumer_key which have created this log entry.
|
||||
# (Maybe we'll want to display this somewhere later.)
|
||||
|
||||
|
||||
Db::execute("
|
||||
insert into okapi_cache_logs (log_id, consumer_key)
|
||||
values (
|
||||
@ -534,7 +630,7 @@ class WebService
|
||||
'".mysql_real_escape_string($consumer_key)."'
|
||||
);
|
||||
");
|
||||
|
||||
|
||||
return $log_uuid;
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,18 @@
|
||||
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>
|
||||
<p><b>Note:</b> Due to <a href='http://code.google.com/p/opencaching-api/issues/detail?id=124'>some issues</a>
|
||||
(which we cannot currently fix), you MAY be allowed to use some basic HTML tags (on some OC installations).
|
||||
However, you should not (this may stop working at any time).</p>
|
||||
<p>Text to be submitted with the log entry.</p>
|
||||
</opt>
|
||||
<opt name='comment_format' default='auto'>
|
||||
<p>Indicates the format of your <b>comment</b>. Three values allowed:
|
||||
<b>auto</b>, <b>html</b> or <b>plaintext</b>. Usually, you should not
|
||||
use the <b>auto</b> option, because its exact behavior is unspecified
|
||||
and may depend on the installation
|
||||
(<a href='https://code.google.com/p/opencaching-api/issues/detail?id=124'>more info</a>).</p>
|
||||
|
||||
<p><b>Important note:</b> The subset of allowed HTML elements is left undefined
|
||||
and may change in the future. For future-compatibility, you should use only
|
||||
basic formatting tags.</p>
|
||||
</opt>
|
||||
<opt name='when'>
|
||||
<p>A date and time string. This should be in ISO 8601 format (currently any
|
||||
|
@ -39,14 +39,14 @@ class WebService
|
||||
$offset = intval($offset);
|
||||
if ($offset < 0)
|
||||
throw new InvalidParam('offset', "'$offset'");
|
||||
|
||||
|
||||
# Check if user exists and retrieve user's ID (this will throw
|
||||
# a proper exception on invalid UUID).
|
||||
$user = OkapiServiceRunner::call('services/users/user', new OkapiInternalRequest(
|
||||
$request->consumer, null, array('user_uuid' => $user_uuid, 'fields' => 'internal_id')));
|
||||
|
||||
|
||||
# User exists. Retrieving logs.
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select cl.id, cl.uuid, cl.type, unix_timestamp(cl.date) as date, cl.text,
|
||||
c.wp_oc as cache_code
|
||||
@ -70,7 +70,7 @@ class WebService
|
||||
'comment' => $row['text']
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class WebService
|
||||
'token_type' => 'request'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$verifier = $request->get_parameter('oauth_verifier');
|
||||
@ -26,9 +26,9 @@ class WebService
|
||||
# We require the 1.0a flow (throw an error when there is no oauth_verifier).
|
||||
throw new ParamMissing("oauth_verifier");
|
||||
}
|
||||
|
||||
|
||||
$new_token = Okapi::$data_store->new_access_token($request->token, $request->consumer, $verifier);
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
$response->body = $new_token;
|
||||
|
@ -17,7 +17,7 @@ class WebService
|
||||
'min_auth_level' => 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$token_key = $request->get_parameter('oauth_token');
|
||||
@ -28,12 +28,12 @@ class WebService
|
||||
if (!$interactivity) $interactivity = 'minimal';
|
||||
if (!in_array($interactivity, array('minimal', 'confirm_user')))
|
||||
throw new InvalidParam('interactivity', $interactivity);
|
||||
|
||||
|
||||
# Redirect to the "apps" folder. This is done there (not here)
|
||||
# because: 1) we don't want any cookie or session-handling
|
||||
# done in the "services" folder. 2) "services" don't display
|
||||
# any interactive webpages, they just return the result.
|
||||
|
||||
|
||||
return new OkapiRedirectResponse(Settings::get('SITE_URL')."okapi/apps/authorize".
|
||||
"?oauth_token=".$token_key.(($langpref != null) ? "&langpref=".$langpref : "").
|
||||
"&interactivity=".$interactivity);
|
||||
|
@ -16,7 +16,7 @@ class WebService
|
||||
'min_auth_level' => 2
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$callback = $request->get_parameter('oauth_callback');
|
||||
@ -25,9 +25,9 @@ class WebService
|
||||
# We require the 1.0a flow (throw an error when there is no oauth_callback).
|
||||
throw new ParamMissing("oauth_callback");
|
||||
}
|
||||
|
||||
|
||||
$new_token = Okapi::$data_store->new_request_token($request->consumer, $callback);
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
$response->body = $new_token."&oauth_callback_confirmed=true";
|
||||
|
@ -23,7 +23,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
@ -31,23 +31,23 @@ class WebService
|
||||
$since = $request->get_parameter('since');
|
||||
if ($since === null) throw new ParamMissing('since');
|
||||
if ((int)$since != $since) throw new InvalidParam('since');
|
||||
|
||||
|
||||
# Let's check the $since parameter.
|
||||
|
||||
|
||||
if (!ReplicateCommon::check_since_param($since))
|
||||
throw new BadRequest("The 'since' parameter is too old. You must update your database more frequently.");
|
||||
|
||||
|
||||
# Select a best chunk for the given $since, get the chunk from the database (or cache).
|
||||
|
||||
|
||||
list($from, $to) = ReplicateCommon::select_best_chunk($since);
|
||||
$clog_entries = ReplicateCommon::get_chunk($from, $to);
|
||||
|
||||
|
||||
$result = array(
|
||||
'changelog' => &$clog_entries,
|
||||
'revision' => $to + 0,
|
||||
'more' => $to < ReplicateCommon::get_revision(),
|
||||
);
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static function count_calls($consumer_key, $days)
|
||||
{
|
||||
return (
|
||||
@ -43,18 +43,18 @@ class WebService
|
||||
")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
|
||||
|
||||
$data = Cache::get("last_fulldump");
|
||||
if ($data == null)
|
||||
throw new BadRequest("No fulldump found. Try again later. If this doesn't help ".
|
||||
"contact site administrator and/or OKAPI developers.");
|
||||
|
||||
|
||||
# Check consumer's quota
|
||||
|
||||
|
||||
$please = $request->get_parameter('pleeaase');
|
||||
if ($please != 'true')
|
||||
{
|
||||
@ -68,7 +68,7 @@ class WebService
|
||||
if ($not_good)
|
||||
throw new BadRequest("No more please. Seriously, dude...");
|
||||
}
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = $data['meta']['content_type'];
|
||||
$response->content_disposition = 'attachment; filename="'.$data['meta']['public_filename'].'"';
|
||||
|
@ -24,7 +24,7 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
require_once('replicate_common.inc.php');
|
||||
@ -46,7 +46,7 @@ class WebService
|
||||
} else {
|
||||
$result['latest_fulldump'] = null;
|
||||
}
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $result);
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,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|was_recommended|comment';
|
||||
|
||||
|
||||
/** Return current (greatest) changelog revision number. */
|
||||
public static function get_revision()
|
||||
{
|
||||
@ -42,7 +42,7 @@ class ReplicateCommon
|
||||
return $cache;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compare two dictionaries. Return the $new dictionary with all unchanged
|
||||
* keys removed. Only the changed ones will remain.
|
||||
@ -64,7 +64,7 @@ class ReplicateCommon
|
||||
$changed[$key] = $new[$key];
|
||||
return $changed;
|
||||
}
|
||||
|
||||
|
||||
/** Check for modifications in the database and update the changelog table accordingly. */
|
||||
public static function update_clog_table()
|
||||
{
|
||||
@ -72,19 +72,19 @@ class ReplicateCommon
|
||||
$last_update = Okapi::get_var('last_clog_update');
|
||||
if ($last_update === null)
|
||||
$last_update = Db::select_value("select date_add(now(), interval -1 day)");
|
||||
|
||||
|
||||
# Usually this will be fast. But, for example, if admin changes ALL the
|
||||
# caches, this will take forever. But we still want it to finish properly
|
||||
# without interruption.
|
||||
|
||||
|
||||
set_time_limit(0);
|
||||
ignore_user_abort(true);
|
||||
|
||||
ignore_user_abort(true);
|
||||
|
||||
# Get the list of modified cache codes. Split it into groups of N cache codes.
|
||||
# Note that we should include ALL cache codes in this particular query, not
|
||||
# only "status in (1,2,3)". This way, when the cache changes its status, e.g.
|
||||
# from 3 to 6, changelog will include a proper "delete" statement.
|
||||
|
||||
|
||||
$cache_codes = Db::select_column("
|
||||
select wp_oc
|
||||
from caches
|
||||
@ -92,17 +92,17 @@ class ReplicateCommon
|
||||
");
|
||||
$cache_code_groups = Okapi::make_groups($cache_codes, 50);
|
||||
unset($cache_codes);
|
||||
|
||||
|
||||
# For each group, update the changelog table accordingly.
|
||||
|
||||
|
||||
foreach ($cache_code_groups as $cache_codes)
|
||||
{
|
||||
self::generate_changelog_entries('services/caches/geocaches', 'geocache', 'cache_codes',
|
||||
'code', $cache_codes, self::$logged_cache_fields, false, true, null);
|
||||
}
|
||||
|
||||
|
||||
# Same as above, for log entries.
|
||||
|
||||
|
||||
$offset = 0;
|
||||
while (true)
|
||||
{
|
||||
@ -129,7 +129,7 @@ class ReplicateCommon
|
||||
# So the above queries won't detect them. We need to run one more.
|
||||
# We will assume there are not so many of them and we don't have to
|
||||
# split them in groups as we did above.
|
||||
|
||||
|
||||
$DELETED_uuids = Db::select_column("
|
||||
select uuid
|
||||
from cache_logs_archived
|
||||
@ -138,9 +138,9 @@ class ReplicateCommon
|
||||
self::generate_changelog_entries('services/logs/entries', 'log', 'log_uuids',
|
||||
'uuid', $DELETED_uuids, self::$logged_log_entry_fields, false, true, 3600);
|
||||
}
|
||||
|
||||
|
||||
# Update state variables.
|
||||
|
||||
|
||||
Okapi::set_var("last_clog_update", $now);
|
||||
$revision = Db::select_value("select max(id) from okapi_clog");
|
||||
Okapi::set_var("clog_revision", $revision);
|
||||
@ -149,7 +149,7 @@ class ReplicateCommon
|
||||
/**
|
||||
* Scan the database and compare the current values of old entries to
|
||||
* the cached values of the same entries. If differences found, update
|
||||
* okapi_syncbase accordingly, and email the admins.
|
||||
* okapi_syncbase accordingly, and email the OKAPI developers.
|
||||
*
|
||||
* Currently, only caches are checked (log entries are not).
|
||||
*/
|
||||
@ -157,12 +157,12 @@ class ReplicateCommon
|
||||
{
|
||||
set_time_limit(0);
|
||||
ignore_user_abort(true);
|
||||
|
||||
|
||||
# We will SKIP the entries which have been modified SINCE one day ago.
|
||||
# Such entries might have not been seen by the update_clog_table() yet
|
||||
# (e.g. other long-running cronjob is preventing update_clog_table from
|
||||
# running).
|
||||
|
||||
|
||||
$cache_codes = Db::select_column("
|
||||
select wp_oc
|
||||
from caches
|
||||
@ -170,11 +170,12 @@ class ReplicateCommon
|
||||
");
|
||||
$cache_code_groups = Okapi::make_groups($cache_codes, 50);
|
||||
unset($cache_codes);
|
||||
|
||||
|
||||
# For each group, get the changelog entries, but don't store them
|
||||
# (the "fulldump" mode). Instead, just update the okapi_syncbase column.
|
||||
|
||||
|
||||
$sum = 0;
|
||||
$two_examples = array();
|
||||
foreach ($cache_code_groups as $cache_codes)
|
||||
{
|
||||
$entries = self::generate_changelog_entries(
|
||||
@ -186,6 +187,14 @@ class ReplicateCommon
|
||||
if ($entry['object_type'] != 'geocache')
|
||||
continue;
|
||||
$cache_code = $entry['object_key']['code'];
|
||||
|
||||
# We will story the first and the last entry in the $two_examples
|
||||
# vars which is to be emailed to OKAPI developers.
|
||||
|
||||
if (count($two_examples) == 0)
|
||||
$two_examples[0] = $entry; /* The first entry */
|
||||
$two_examples[1] = $entry; /* The last entry */
|
||||
|
||||
Db::execute("
|
||||
update caches
|
||||
set okapi_syncbase = now()
|
||||
@ -196,16 +205,20 @@ class ReplicateCommon
|
||||
}
|
||||
if ($sum > 0)
|
||||
{
|
||||
$message = (
|
||||
"Number of invalid entries scheduled to be fixed: $sum\n".
|
||||
"Approx revision of the first one: ".Okapi::get_var('clog_revision')."\n\n".
|
||||
"Two examples:\n\n".print_r($two_examples, true)
|
||||
);
|
||||
Okapi::mail_from_okapi(
|
||||
"rygielski@mimuw.edu.pl",
|
||||
"verify_clog_consistency",
|
||||
"Number of invalid entries fixed: $sum\n\n".
|
||||
print_r(Db::select_all("select * from okapi_vars"), true)
|
||||
"verify_clog_consistency - ".Okapi::get_normalized_site_name(),
|
||||
$message, true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate OKAPI changelog entries. This method will call $feeder_method OKAPI
|
||||
* service with the following parameters: array($feeder_keys_param => implode('|', $key_values),
|
||||
@ -223,7 +236,7 @@ class ReplicateCommon
|
||||
$key_name, $key_values, $fields, $fulldump_mode, $use_cache, $cache_timeout = 86400)
|
||||
{
|
||||
# Retrieve the previous versions of all objects from OKAPI cache.
|
||||
|
||||
|
||||
if ($use_cache)
|
||||
{
|
||||
$cache_keys1 = array();
|
||||
@ -242,10 +255,10 @@ class ReplicateCommon
|
||||
unset($cache_keys1);
|
||||
unset($cache_keys2);
|
||||
}
|
||||
|
||||
|
||||
# Get the current values for objects. Compare them with their previous versions
|
||||
# and generate changelog entries.
|
||||
|
||||
|
||||
require_once($GLOBALS['rootpath'].'okapi/service_runner.php');
|
||||
$current_values = OkapiServiceRunner::call($feeder_method, new OkapiInternalRequest(
|
||||
new OkapiInternalConsumer(), null, array($feeder_keys_param => implode("|", $key_values),
|
||||
@ -310,7 +323,7 @@ class ReplicateCommon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($fulldump_mode)
|
||||
{
|
||||
return $entries;
|
||||
@ -318,7 +331,7 @@ class ReplicateCommon
|
||||
else
|
||||
{
|
||||
# Save the entries to the clog table.
|
||||
|
||||
|
||||
if (count($entries) > 0)
|
||||
{
|
||||
$data_values = array();
|
||||
@ -329,9 +342,9 @@ class ReplicateCommon
|
||||
values ('".implode("'),('", array_map('mysql_real_escape_string', $data_values))."');
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
# Update the values kept in OKAPI cache.
|
||||
|
||||
|
||||
if ($use_cache)
|
||||
{
|
||||
Cache::set_many($cached_values1, $cache_timeout);
|
||||
@ -339,7 +352,7 @@ class ReplicateCommon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the 'since' parameter is up-do-date. If it is not, then it means
|
||||
* that the user waited too long and he has to download the fulldump again.
|
||||
@ -350,16 +363,16 @@ class ReplicateCommon
|
||||
select id from okapi_clog where id > '".mysql_real_escape_string($since)."' limit 1
|
||||
");
|
||||
if ($first_id === null)
|
||||
return true; # okay, since points to the newest revision
|
||||
return true; # okay, since points to the newest revision
|
||||
if ($first_id == $since + 1)
|
||||
return true; # okay, revision $since + 1 is present
|
||||
|
||||
|
||||
# If we're here, then this means that $first_id > $since + 1.
|
||||
# Revision $since + 1 is already deleted, $since must be too old!
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Select best chunk for a given $since parameter. This function will try to select
|
||||
* one chunk for different values of $since parameter, this is done in order to
|
||||
@ -377,7 +390,7 @@ class ReplicateCommon
|
||||
# which we probably already have in cache (and this includes the 50 which the
|
||||
# user wants), then we'll give him 80. If user wants less than half of what we
|
||||
# have (ex. 30), then we'll give him only his 30.
|
||||
|
||||
|
||||
if ($current_revision - $since > $since - $last_chunk_cut)
|
||||
return array($last_chunk_cut + 1, $current_revision);
|
||||
else
|
||||
@ -386,7 +399,7 @@ class ReplicateCommon
|
||||
$prev_chunk_cut = $since - ($since % self::$chunk_size);
|
||||
return array($prev_chunk_cut + 1, $prev_chunk_cut + self::$chunk_size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return changelog chunk, starting at $from, ending as $to.
|
||||
*/
|
||||
@ -396,9 +409,9 @@ class ReplicateCommon
|
||||
return array();
|
||||
if ($to - $from > self::$chunk_size)
|
||||
throw new Exception("You should not get chunksize bigger than ".self::$chunk_size." entries at one time.");
|
||||
|
||||
|
||||
# Check if we already have this chunk in cache.
|
||||
|
||||
|
||||
$cache_key = 'clog_chunk#'.$from.'-'.$to;
|
||||
$chunk = Cache::get($cache_key);
|
||||
if ($chunk === null)
|
||||
@ -414,23 +427,23 @@ class ReplicateCommon
|
||||
{
|
||||
$chunk[] = unserialize(gzinflate($row['data']));
|
||||
}
|
||||
|
||||
|
||||
# Cache timeout depends on the chunk starting and ending point. Chunks
|
||||
# which start and end on the boundries of chunk_size should be cached
|
||||
# longer (they can be accessed even after 10 days). Other chunks won't
|
||||
# be ever accessed after the next revision appears, so there is not point
|
||||
# in storing them that long.
|
||||
|
||||
|
||||
if (($from % self::$chunk_size === 0) && ($to % self::$chunk_size === 0))
|
||||
$timeout = 10 * 86400;
|
||||
else
|
||||
$timeout = 86400;
|
||||
Cache::set($cache_key, $chunk, $timeout);
|
||||
}
|
||||
|
||||
|
||||
return $chunk;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a new fulldump file and put it into the OKAPI cache table.
|
||||
* Return the cache key.
|
||||
@ -438,22 +451,22 @@ class ReplicateCommon
|
||||
public static function generate_fulldump()
|
||||
{
|
||||
# First we will create temporary files, then compress them in the end.
|
||||
|
||||
|
||||
$revision = self::get_revision();
|
||||
$generated_at = date('c', time());
|
||||
$dir = Okapi::get_var_dir()."/okapi-db-dump";
|
||||
$i = 1;
|
||||
$json_files = array();
|
||||
|
||||
|
||||
# Cleanup (from a previous, possibly unsuccessful, execution)
|
||||
|
||||
|
||||
shell_exec("rm -f $dir/*");
|
||||
shell_exec("rmdir $dir");
|
||||
shell_exec("mkdir $dir");
|
||||
shell_exec("chmod 777 $dir");
|
||||
|
||||
|
||||
# Geocaches
|
||||
|
||||
|
||||
$cache_codes = Db::select_column("select wp_oc from caches");
|
||||
$cache_code_groups = Okapi::make_groups($cache_codes, 200);
|
||||
unset($cache_codes);
|
||||
@ -473,10 +486,10 @@ class ReplicateCommon
|
||||
$i++;
|
||||
}
|
||||
unset($cache_code_groups);
|
||||
|
||||
|
||||
# Log entries. We cannot load all the uuids at one time, this would take
|
||||
# too much memory. Hence the offset/limit loop.
|
||||
|
||||
|
||||
$offset = 0;
|
||||
while (true)
|
||||
{
|
||||
@ -508,9 +521,9 @@ class ReplicateCommon
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Package data.
|
||||
|
||||
|
||||
$metadata = array(
|
||||
'revision' => $revision,
|
||||
'data_files' => $json_files,
|
||||
@ -521,32 +534,32 @@ class ReplicateCommon
|
||||
),
|
||||
);
|
||||
file_put_contents("$dir/index.json", json_encode($metadata));
|
||||
|
||||
|
||||
# Compute uncompressed size.
|
||||
|
||||
|
||||
$size = filesize("$dir/index.json");
|
||||
foreach ($json_files as $filename)
|
||||
$size += filesize("$dir/$filename");
|
||||
|
||||
|
||||
# Create JSON archive. We use tar options: -j for bzip2, -z for gzip
|
||||
# (bzip2 is MUCH slower).
|
||||
|
||||
|
||||
$use_bzip2 = true;
|
||||
$dumpfilename = "okapi-dump.tar.".($use_bzip2 ? "bz2" : "gz");
|
||||
shell_exec("tar --directory $dir -c".($use_bzip2 ? "j" : "z")."f $dir/$dumpfilename index.json ".implode(" ", $json_files). " 2>&1");
|
||||
|
||||
|
||||
# Delete temporary files.
|
||||
|
||||
|
||||
shell_exec("rm -f $dir/*.json");
|
||||
|
||||
|
||||
# Move the archive one directory upwards, replacing the previous one.
|
||||
# Remove the temporary directory.
|
||||
|
||||
|
||||
shell_exec("mv -f $dir/$dumpfilename ".Okapi::get_var_dir());
|
||||
shell_exec("rmdir $dir");
|
||||
|
||||
|
||||
# Update the database info.
|
||||
|
||||
|
||||
$metadata['meta']['filepath'] = Okapi::get_var_dir().'/'.$dumpfilename;
|
||||
$metadata['meta']['content_type'] = ($use_bzip2 ? "application/octet-stream" : "application/x-gzip");
|
||||
$metadata['meta']['public_filename'] = 'okapi-dump-r'.$metadata['revision'].'.tar.'.($use_bzip2 ? "bz2" : "gz");
|
||||
|
@ -25,9 +25,9 @@ class WebService
|
||||
$internal_id = $request->get_parameter('internal_id');
|
||||
if (!$internal_id) throw new ParamMissing('internal_id');
|
||||
$fields = $request->get_parameter('fields');
|
||||
|
||||
|
||||
# There's no need to validate the fields parameter.
|
||||
|
||||
|
||||
$results = OkapiServiceRunner::call('services/users/by_internal_ids', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('internal_ids' => $internal_id,
|
||||
'fields' => $fields)));
|
||||
|
@ -31,10 +31,10 @@ class WebService
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields)
|
||||
throw new ParamMissing('fields');
|
||||
|
||||
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select user_id, uuid
|
||||
from user
|
||||
@ -46,12 +46,12 @@ class WebService
|
||||
$internalid2useruuid[$row['user_id']] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
|
||||
# Retrieve data on given user_uuids.
|
||||
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($internalid2useruuid)),
|
||||
'fields' => $fields)));
|
||||
|
||||
|
||||
# Map user_uuids to internal_ids. Also check which internal_ids were not found
|
||||
# and mark them with null.
|
||||
$results = array();
|
||||
@ -62,7 +62,7 @@ class WebService
|
||||
else
|
||||
$results[$internal_id] = $id_results[$internalid2useruuid[$internal_id]];
|
||||
}
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +28,9 @@ class WebService
|
||||
$username = $request->get_parameter('username');
|
||||
if (!$username) throw new ParamMissing('username');
|
||||
$fields = $request->get_parameter('fields');
|
||||
|
||||
|
||||
# There's no need to validate the fields parameter.
|
||||
|
||||
|
||||
$results = OkapiServiceRunner::call('services/users/by_usernames', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('usernames' => $username,
|
||||
'fields' => $fields)));
|
||||
|
@ -31,10 +31,10 @@ class WebService
|
||||
$fields = $request->get_parameter('fields');
|
||||
if (!$fields)
|
||||
throw new ParamMissing('fields');
|
||||
|
||||
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select username, uuid
|
||||
from user
|
||||
@ -46,12 +46,12 @@ class WebService
|
||||
$username2useruuid[$row['username']] = $row['uuid'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
|
||||
# Retrieve data on given user_uuids.
|
||||
$id_results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => implode("|", array_values($username2useruuid)),
|
||||
'fields' => $fields)));
|
||||
|
||||
|
||||
# Map user_uuids to usernames. Also check which usernames were not found
|
||||
# and mark them with null.
|
||||
$results = array();
|
||||
@ -62,7 +62,7 @@ class WebService
|
||||
else
|
||||
$results[$username] = $id_results[$username2useruuid[$username]];
|
||||
}
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -41,10 +41,10 @@ class WebService
|
||||
}
|
||||
}
|
||||
$fields = $request->get_parameter('fields');
|
||||
|
||||
|
||||
# There's no need to validate the fields parameter as the 'users'
|
||||
# method does this (it will raise a proper exception on invalid values).
|
||||
|
||||
|
||||
$results = OkapiServiceRunner::call('services/users/users', new OkapiInternalRequest(
|
||||
$request->consumer, $request->token, array('user_uuids' => $user_uuid,
|
||||
'fields' => $fields)));
|
||||
|
@ -19,10 +19,10 @@ class WebService
|
||||
'min_auth_level' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static $valid_field_names = array('uuid', 'username', 'profile_url', 'internal_id', 'is_admin',
|
||||
'caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given');
|
||||
|
||||
|
||||
public static function call(OkapiRequest $request)
|
||||
{
|
||||
$user_uuids = $request->get_parameter('user_uuids');
|
||||
@ -78,21 +78,21 @@ class WebService
|
||||
$results[$row['uuid']] = $entry;
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
|
||||
# caches_found, caches_notfound, caches_hidden
|
||||
|
||||
|
||||
if (in_array('caches_found', $fields) || in_array('caches_notfound', $fields) || in_array('caches_hidden', $fields)
|
||||
|| in_array('rcmds_given', $fields))
|
||||
{
|
||||
# We will load all these stats together. Then we may remove these which
|
||||
# the user doesn't need.
|
||||
|
||||
|
||||
$extras = array();
|
||||
|
||||
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
{
|
||||
# OCPL stores user stats in 'user' table.
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select user_id, founds_count, notfounds_count, hidden_count
|
||||
from user
|
||||
@ -102,7 +102,7 @@ class WebService
|
||||
else
|
||||
{
|
||||
# OCDE stores user stats in 'stat_user' table.
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select
|
||||
u.user_id,
|
||||
@ -116,7 +116,7 @@ class WebService
|
||||
where u.user_id in ('".implode("','", array_map('mysql_real_escape_string', array_keys($id2uuid)))."')
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
{
|
||||
$extras[$row['user_id']] = array();;
|
||||
@ -126,7 +126,7 @@ class WebService
|
||||
$extra_ref['caches_hidden'] = 0 + $row['hidden_count'];
|
||||
}
|
||||
mysql_free_result($rs);
|
||||
|
||||
|
||||
if (in_array('rcmds_given', $fields))
|
||||
{
|
||||
$rs = Db::query("
|
||||
@ -143,9 +143,9 @@ class WebService
|
||||
$extra_ref['rcmds_given'] = isset($rcmds_counts[$user_id]) ? 0 + $rcmds_counts[$user_id] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# "Apply" only those fields which the consumer wanted.
|
||||
|
||||
|
||||
foreach (array('caches_found', 'caches_notfound', 'caches_hidden', 'rcmds_given') as $field)
|
||||
{
|
||||
if (!in_array($field, $fields))
|
||||
@ -154,13 +154,13 @@ class WebService
|
||||
$result_ref[$field] = $extras[$uuid2id[$uuid]][$field];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Check which user IDs were not found and mark them with null.
|
||||
|
||||
|
||||
foreach ($user_uuids as $user_uuid)
|
||||
if (!isset($results[$user_uuid]))
|
||||
$results[$user_uuid] = null;
|
||||
|
||||
|
||||
return Okapi::formatted_response($request, $results);
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ final class Settings
|
||||
throw new Exception("IMAGES_DIR cannot be null. Please provide a valid directory.");
|
||||
foreach ($dict as $k => $v)
|
||||
if ((strpos($k, '_DIR') !== false) && ($k[strlen($k) - 1] == '/'))
|
||||
throw new Exception("All *_DIR settings may not end with a slash. Check $k.");
|
||||
throw new Exception("None of the *_DIR settings may end with a slash. Check $k.");
|
||||
$notnull = array('OC_COOKIE_NAME', 'DB_SERVER', 'DB_NAME', 'DB_USERNAME', 'SITE_URL', 'OC_NODE_ID');
|
||||
foreach ($notnull as $k)
|
||||
if ($dict[$k] === null)
|
||||
|
@ -26,6 +26,7 @@ class OkapiUrls
|
||||
'^devel/dbstruct$' => 'devel/dbstruct',
|
||||
'^devel/cronreport$' => 'devel/cronreport',
|
||||
'^devel/tilereport$' => 'devel/tilereport',
|
||||
'^devel/clogentry$' => 'devel/clogentry',
|
||||
|
||||
# For debugging TileMap performance only.
|
||||
// '^tilestress$' => 'tilestress',
|
||||
|
@ -22,13 +22,13 @@ class View
|
||||
$locales = array();
|
||||
foreach (Locales::$languages as $lang => $attrs)
|
||||
$locales[$attrs['locale']] = $attrs;
|
||||
|
||||
|
||||
# Current implementation of the "interactivity" parameter is: If developer
|
||||
# wants to "confirm_user", then just log out the current user before we
|
||||
# continue.
|
||||
|
||||
|
||||
$force_relogin = (isset($_GET['interactivity']) && $_GET['interactivity'] == 'confirm_user');
|
||||
|
||||
|
||||
$token = Db::select_row("
|
||||
select
|
||||
t.`key` as `key`,
|
||||
@ -45,14 +45,14 @@ class View
|
||||
and t.consumer_key = c.`key`
|
||||
and t.user_id is null
|
||||
");
|
||||
|
||||
|
||||
$callback_concat_char = (strpos($token['callback'], '?') === false) ? "?" : "&";
|
||||
|
||||
|
||||
if (!$token)
|
||||
{
|
||||
# Probably Request Token has expired. This will be usually viewed
|
||||
# by the user, who knows nothing on tokens and OAuth. Let's be nice then!
|
||||
|
||||
|
||||
$vars = array(
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
'token' => $token,
|
||||
@ -69,14 +69,14 @@ class View
|
||||
Okapi::gettext_domain_restore();
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
# Determine which user is logged in to OC.
|
||||
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/lib/oc_session.php");
|
||||
$OC_user_id = OCSession::get_user_id();
|
||||
|
||||
|
||||
# Ensure a user is logged in (or force re-login).
|
||||
|
||||
|
||||
if ($force_relogin || ($OC_user_id == null))
|
||||
{
|
||||
if ($force_relogin)
|
||||
@ -85,14 +85,14 @@ class View
|
||||
# The logout.php DOES NOT support the "target" parameter, so we
|
||||
# can't just call it. The only thing that comes to mind is...
|
||||
# Destroy EVERYTHING.
|
||||
|
||||
|
||||
$past = time() - 86400;
|
||||
foreach ($_COOKIE as $key => $value)
|
||||
setcookie($key, $value, $past, '/');
|
||||
}
|
||||
|
||||
|
||||
# We should be logged out now. Let's login again.
|
||||
|
||||
|
||||
$after_login = "okapi/apps/authorize?oauth_token=$token_key".(($langpref != Settings::get('SITELANG'))?"&langpref=".$langpref:"");
|
||||
$login_url = Settings::get('SITE_URL')."login.php?target=".urlencode($after_login)
|
||||
."&langpref=".$langpref;
|
||||
@ -117,11 +117,11 @@ class View
|
||||
{
|
||||
# Not yet authorized, but user have just submitted the authorization form.
|
||||
# WRTODO: CSRF protection
|
||||
|
||||
|
||||
if ($_POST['authorization_result'] == 'granted')
|
||||
{
|
||||
Db::execute("
|
||||
insert into okapi_authorizations (consumer_key, user_id)
|
||||
insert ignore into okapi_authorizations (consumer_key, user_id)
|
||||
values (
|
||||
'".mysql_real_escape_string($token['consumer_key'])."',
|
||||
'".mysql_real_escape_string($OC_user_id)."'
|
||||
@ -133,7 +133,7 @@ class View
|
||||
{
|
||||
# User denied access. Nothing sensible to do now. Will try to report
|
||||
# back to the Consumer application with an error.
|
||||
|
||||
|
||||
if ($token['callback']) {
|
||||
return new OkapiRedirectResponse($token['callback'].$callback_concat_char."error=access_denied");
|
||||
} else {
|
||||
@ -162,17 +162,17 @@ class View
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# User granted access. Now we can authorize the Request Token.
|
||||
|
||||
|
||||
Db::execute("
|
||||
update okapi_tokens
|
||||
set user_id = '".mysql_real_escape_string($OC_user_id)."'
|
||||
where `key` = '".mysql_real_escape_string($token_key)."';
|
||||
");
|
||||
|
||||
|
||||
# Redirect to the callback_url.
|
||||
|
||||
|
||||
if ($token['callback']) {
|
||||
return new OkapiRedirectResponse($token['callback'].$callback_concat_char."oauth_token=".$token_key."&oauth_verifier=".$token['verifier']);
|
||||
} else {
|
||||
|
@ -32,7 +32,7 @@
|
||||
<a href='<?= $vars['okapi_base_url'] ?>'><img src='<?= $vars['okapi_base_url'] ?>static/logo-xsmall.gif' alt='OKAPI' style='float: right; margin-left: 10px;'></a>
|
||||
<a href='/'><img src="/images/oc_logo.png" alt='OpenCaching' style='float: left; margin-right: 10px'></a>
|
||||
<a class='opencaching'><?= $vars['site_name'] ?></a>
|
||||
|
||||
|
||||
<div style='float: right; clear: right; margin: 10px 0 10px 30px'>
|
||||
Choose your language:
|
||||
<select id='langpref' style='border: 1px solid #ccc'>
|
||||
@ -41,7 +41,7 @@
|
||||
<? } ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<? if (isset($vars['token_expired']) && $vars['token_expired']) { ?>
|
||||
<h1 style='clear: both'><?= _("Expired request") ?></h1>
|
||||
<p><?= _("Unfortunately, the request has expired. Please try again.") ?></p>
|
||||
|
@ -18,7 +18,7 @@ class View
|
||||
$verifier = isset($_GET['oauth_verifier']) ? $_GET['oauth_verifier'] : '';
|
||||
$langpref = isset($_GET['langpref']) ? $_GET['langpref'] : Settings::get('SITELANG');
|
||||
$langprefs = explode("|", $langpref);
|
||||
|
||||
|
||||
$token = Db::select_row("
|
||||
select
|
||||
c.`key` as consumer_key,
|
||||
@ -39,7 +39,7 @@ class View
|
||||
# just redirect to the OpenCaching main page.
|
||||
return new OkapiRedirectResponse(Settings::get('SITE_URL'));
|
||||
}
|
||||
|
||||
|
||||
$vars = array(
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
'token' => $token,
|
||||
|
@ -19,20 +19,20 @@
|
||||
.okapi .pin { margin: 20px 20px 20px 0; background: #eee; border: 1px solid #ccc; padding: 20px 40px; text-align: center; font-size: 24px; }
|
||||
</style>
|
||||
<body>
|
||||
|
||||
|
||||
<div class='okapi'>
|
||||
<a href='<?= $vars['okapi_base_url'] ?>'><img src='<?= $vars['okapi_base_url'] ?>static/logo-xsmall.gif' alt='OKAPI' style='float: right; margin-left: 10px;'></a>
|
||||
<a href='/'><img src="/images/oc_logo.png" alt='OpenCaching' style='float: left; margin-right: 10px'></a>
|
||||
<a class='opencaching'><?= $vars['site_name'] ?></a>
|
||||
|
||||
|
||||
<h1 style='clear: both'><?= _("Access successfully granted") ?></h1>
|
||||
<?= sprintf(_("
|
||||
<p><b>You've just granted %s application access to your %s account.</b>
|
||||
To complete the operation, go back to %s and enter the following PIN code:</p>
|
||||
"), $vars['token']['consumer_name'], $vars['site_name'], $vars['token']['consumer_name']) ?>
|
||||
|
||||
|
||||
<div class='pin'><?= $vars['verifier'] ?></div>
|
||||
|
||||
|
||||
<p><a href='/'><?= $vars['site_name'] ?></a></p>
|
||||
</div>
|
||||
|
||||
|
@ -17,9 +17,9 @@ class View
|
||||
{
|
||||
$langpref = isset($_GET['langpref']) ? $_GET['langpref'] : Settings::get('SITELANG');
|
||||
$langprefs = explode("|", $langpref);
|
||||
|
||||
|
||||
# Determine which user is logged in to OC.
|
||||
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/lib/oc_session.php");
|
||||
$OC_user_id = OCSession::get_user_id();
|
||||
|
||||
@ -29,9 +29,9 @@ class View
|
||||
$login_url = Settings::get('SITE_URL')."login.php?target=".urlencode($after_login);
|
||||
return new OkapiRedirectResponse($login_url);
|
||||
}
|
||||
|
||||
|
||||
# Get the list of authorized apps.
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select c.`key`, c.name, c.url
|
||||
from
|
||||
@ -49,7 +49,7 @@ class View
|
||||
while ($row = mysql_fetch_assoc($rs))
|
||||
$vars['apps'][] = $row;
|
||||
mysql_free_result($rs);
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/html; charset=utf-8";
|
||||
ob_start();
|
||||
|
@ -25,7 +25,7 @@
|
||||
<a href='<?= $vars['okapi_base_url'] ?>'><img src='<?= $vars['okapi_base_url'] ?>static/logo-xsmall.gif' alt='OKAPI' style='float: right; margin-left: 10px;'></a>
|
||||
<a href='/'><img src="<?= $vars['okapi_base_url'] ?>static/oc_logo.png" alt='OpenCaching' style='float: left; margin-right: 10px'></a>
|
||||
<a class='opencaching'><?= $vars['site_name'] ?></a>
|
||||
|
||||
|
||||
<h1 style='clear: both'><?= _("Your external applications") ?></h1>
|
||||
<? if (count($vars['apps']) > 0) { ?>
|
||||
<?= sprintf(_("
|
||||
|
@ -16,23 +16,23 @@ class View
|
||||
public static function call()
|
||||
{
|
||||
# Determine which user is logged in to OC.
|
||||
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/lib/oc_session.php");
|
||||
$OC_user_id = OCSession::get_user_id();
|
||||
|
||||
|
||||
# Ensure a user is logged in.
|
||||
|
||||
|
||||
if ($OC_user_id == null)
|
||||
{
|
||||
$after_login = "okapi/apps/"; # it is correct, if you're wondering
|
||||
$login_url = Settings::get('SITE_URL')."login.php?target=".urlencode($after_login);
|
||||
return new OkapiRedirectResponse($login_url);
|
||||
}
|
||||
|
||||
|
||||
$consumer_key = isset($_REQUEST['consumer_key']) ? $_REQUEST['consumer_key'] : '';
|
||||
|
||||
|
||||
# Just remove app (if it doesn't exist - nothing wrong will happen anyway).
|
||||
|
||||
|
||||
Db::execute("
|
||||
delete from okapi_tokens
|
||||
where
|
||||
@ -45,9 +45,9 @@ class View
|
||||
user_id = '".mysql_real_escape_string($OC_user_id)."'
|
||||
and consumer_key = '".mysql_real_escape_string($consumer_key)."'
|
||||
");
|
||||
|
||||
|
||||
# Redirect back to the apps page.
|
||||
|
||||
|
||||
return new OkapiRedirectResponse(Settings::get('SITE_URL')."okapi/apps/");
|
||||
}
|
||||
}
|
||||
|
@ -26,13 +26,13 @@ class View
|
||||
ignore_user_abort(true);
|
||||
set_time_limit(0);
|
||||
header("Content-Type: text/plain; charset=utf-8");
|
||||
|
||||
|
||||
# Uncomment the following if you want to debug a specific cronjob. It will be run
|
||||
# every 5 minutes (run 'crontab -e' to change or disable it) AND additionally
|
||||
# every time you visit http://yoursite/okapi/cron5
|
||||
|
||||
|
||||
# require_once($GLOBALS['rootpath']."okapi/cronjobs.php"); CronJobController::force_run("JOB_NAME"); die();
|
||||
|
||||
|
||||
Okapi::execute_cron5_cronjobs();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
View in this directory are NOT services. They can disappear at any time.
|
||||
Views in this directory are NOT services. They can disappear at any time.
|
||||
|
||||
These views help us develop OKAPI in a proper way across different OC
|
||||
installations. They do not (or at least should not) expose any sensitive
|
||||
|
@ -21,17 +21,17 @@ class View
|
||||
{
|
||||
# This is a hidden page for OKAPI developers. It will list all
|
||||
# attributes defined in this OC installation (and some other stuff).
|
||||
|
||||
|
||||
ob_start();
|
||||
|
||||
|
||||
print "Cache Types:\n\n";
|
||||
foreach (self::get_all_cachetypes() as $id => $name)
|
||||
print "$id: $name\n";
|
||||
|
||||
|
||||
print "\nLog Types:\n\n";
|
||||
foreach (self::get_all_logtypes() as $id => $name)
|
||||
print "$id: $name\n";
|
||||
|
||||
|
||||
print "\nAttributes:\n\n";
|
||||
$dict = Okapi::get_all_atribute_names();
|
||||
foreach ($dict as $internal_id => $langs)
|
||||
@ -46,6 +46,19 @@ class View
|
||||
foreach ($langkeys as $langkey)
|
||||
print " $langkey: ".$langs[$langkey]."\n";
|
||||
}
|
||||
foreach ($dict as $internal_id => $langs)
|
||||
{
|
||||
print "<attr okapi_attr_id=\"TODO\">\n";
|
||||
print "\t<groundspeak id=\"TODO\" inc=\"TODO\" name=\"TODO\" />\n";
|
||||
print "\t<opencaching site_url=\"SITEURLTODO\" id=\"$internal_id\" />\n";
|
||||
$langkeys = array_keys($langs);
|
||||
usort($langkeys, function($a, $b) {
|
||||
return ($a == "en") ? -1 : (($a == $b) ? 0 : (($a < $b) ? -1 : 1));
|
||||
});
|
||||
foreach ($langkeys as $langkey)
|
||||
print "\t<name lang=\"$langkey\">".$langs[$langkey]."</name>\n";
|
||||
print "</attr>\n";
|
||||
}
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
@ -61,13 +74,13 @@ class View
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
{
|
||||
# OCPL branch does not store cache types in many languages (just two).
|
||||
|
||||
|
||||
$rs = Db::query("select id, en from cache_type order by id");
|
||||
}
|
||||
else
|
||||
{
|
||||
# OCDE branch uses translation tables.
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select
|
||||
ct.id,
|
||||
@ -80,14 +93,14 @@ class View
|
||||
order by ct.id
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
$dict = array();
|
||||
while ($row = mysql_fetch_assoc($rs)) {
|
||||
$dict[$row['id']] = $row['en'];
|
||||
}
|
||||
return $dict;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an array of all site-specific log-types (id => name in English).
|
||||
*/
|
||||
@ -96,13 +109,13 @@ class View
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
{
|
||||
# OCPL branch does not store cache types in many languages (just two).
|
||||
|
||||
|
||||
$rs = Db::query("select id, en from log_types order by id");
|
||||
}
|
||||
else
|
||||
{
|
||||
# OCDE branch uses translation tables.
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select
|
||||
lt.id,
|
||||
@ -115,7 +128,7 @@ class View
|
||||
order by lt.id
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
$dict = array();
|
||||
while ($row = mysql_fetch_assoc($rs)) {
|
||||
$dict[$row['id']] = $row['en'];
|
||||
|
34
htdocs/okapi/views/devel/clogentry.php
Normal file
34
htdocs/okapi/views/devel/clogentry.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace okapi\views\devel\clogentry;
|
||||
|
||||
use Exception;
|
||||
use okapi\Okapi;
|
||||
use okapi\Cache;
|
||||
use okapi\Db;
|
||||
use okapi\OkapiRequest;
|
||||
use okapi\OkapiRedirectResponse;
|
||||
use okapi\OkapiHttpResponse;
|
||||
use okapi\ParamMissing;
|
||||
use okapi\InvalidParam;
|
||||
use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use okapi\Settings;
|
||||
|
||||
class View
|
||||
{
|
||||
public static function call()
|
||||
{
|
||||
$tmp = Db::select_value("
|
||||
select data
|
||||
from okapi_clog
|
||||
where id='".mysql_real_escape_string($_GET['id'])."'
|
||||
");
|
||||
$data = unserialize(gzinflate($tmp));
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "application/json; charset=utf-8";
|
||||
$response->body = json_encode($data);
|
||||
return $response;
|
||||
}
|
||||
}
|
@ -181,13 +181,13 @@ class dbStructUpdater
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets structured general info about the databases diff :
|
||||
* array(sourceOrphans=>array(...), destOrphans=>array(...), different=>array(...))
|
||||
*/
|
||||
function getDiffInfo($compRes)
|
||||
{
|
||||
{
|
||||
if (!is_array($compRes))
|
||||
{
|
||||
return false;
|
||||
@ -251,10 +251,10 @@ class dbStructUpdater
|
||||
$info['sourceOrphan'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
$destSql = $this->getTabSql($this->destStruct, $tab, true);
|
||||
$sourceSql = $this->getTabSql($this->sourceStruct, $tab, true);
|
||||
$diffs = $this->compareSql($sourceSql, $destSql);
|
||||
$diffs = $this->compareSql($sourceSql, $destSql);
|
||||
if ($diffs===false)
|
||||
{
|
||||
trigger_error('[WARNING] error parsing definition of table "'.$tab.'" - skipped');
|
||||
@ -262,8 +262,8 @@ class dbStructUpdater
|
||||
}
|
||||
elseif (!empty($diffs))//not empty array
|
||||
{
|
||||
$info['differs'] = $diffs;
|
||||
}
|
||||
$info['differs'] = $diffs;
|
||||
}
|
||||
else continue;//empty array
|
||||
}
|
||||
$result[$tab] = $info;
|
||||
@ -302,7 +302,7 @@ class dbStructUpdater
|
||||
$result = '';
|
||||
/* create table should be single line in this case*/
|
||||
//1 - part before database, 2-database name, 3 - part after database
|
||||
if (preg_match('/(CREATE(?:\s*TEMPORARY)?\s*TABLE\s*(?:IF NOT EXISTS\s*)?)(?:`?(\w+)`?\.)?(`?('.$tab.')`?(\W|$))/i', $struct, $m, PREG_OFFSET_CAPTURE))
|
||||
if (preg_match('/(CREATE(?:\s*TEMPORARY)?\s*TABLE\s*(?:IF NOT EXISTS\s*)?)(?:`?(\w+)`?\.)?(`?('.$tab.')`?(\W|$))/i', $struct, $m, PREG_OFFSET_CAPTURE))
|
||||
{
|
||||
$tableDef = $m[0][0];
|
||||
$start = $m[0][1];
|
||||
@ -322,13 +322,13 @@ class dbStructUpdater
|
||||
if ($database && $removeDatabase)
|
||||
{
|
||||
$result = str_replace($tableDef, $m[1][0].$m[3][0], $result);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Splits table sql into indexed array
|
||||
*
|
||||
*
|
||||
*/
|
||||
function splitTabSql($sql)
|
||||
{
|
||||
@ -387,7 +387,7 @@ class dbStructUpdater
|
||||
*/
|
||||
function compareSql($sourceSql, $destSql)//$sourceSql, $destSql
|
||||
{
|
||||
$result = array();
|
||||
$result = array();
|
||||
//split with comma delimiter, not line breaks
|
||||
$sourceParts = $this->splitTabSql($sourceSql);
|
||||
if ($sourceParts===false)//error parsing sql
|
||||
@ -404,13 +404,13 @@ class dbStructUpdater
|
||||
$sourcePartsIndexed = array();
|
||||
$destPartsIndexed = array();
|
||||
foreach($sourceParts as $line)
|
||||
{
|
||||
{
|
||||
$lineInfo = $this->processLine($line);
|
||||
if (!$lineInfo) continue;
|
||||
$sourcePartsIndexed[$lineInfo['key']] = $lineInfo['line'];
|
||||
}
|
||||
foreach($destParts as $line)
|
||||
{
|
||||
{
|
||||
$lineInfo = $this->processLine($line);
|
||||
if (!$lineInfo) continue;
|
||||
$destPartsIndexed[$lineInfo['key']] = $lineInfo['line'];
|
||||
@ -427,7 +427,7 @@ class dbStructUpdater
|
||||
$inDest= in_array($key, $destKeys);
|
||||
$sourceOrphan = $inSource && !$inDest;
|
||||
$destOrphan = $inDest && !$inSource;
|
||||
$different = $inSource && $inDest &&
|
||||
$different = $inSource && $inDest &&
|
||||
strcasecmp($this->normalizeString($destPartsIndexed[$key]), $this->normalizeString($sourcePartsIndexed[$key]));
|
||||
if ($sourceOrphan)
|
||||
{
|
||||
@ -657,11 +657,11 @@ class dbStructUpdater
|
||||
$rbs = '\\\\'; //reg - escaped backslash
|
||||
$regPrefix = "(?<!$rbs)(?:$rbs{2})*";
|
||||
$reg = $regPrefix.'("|\')|(/\\*)|(\\*/)|(-- )|(\r\n|\r|\n)|';
|
||||
if ($skipInBrackets)
|
||||
if ($skipInBrackets)
|
||||
{
|
||||
$reg.='(\(|\))|';
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
$reg.='()';
|
||||
}
|
||||
@ -730,7 +730,7 @@ class dbStructUpdater
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* works the same as getDelimPos except returns position of the first occurence of the delimiter starting from
|
||||
* the end of the string
|
||||
|
@ -21,11 +21,11 @@ class View
|
||||
{
|
||||
# This is a hidden page for OKAPI developers. It will output a cronjobs
|
||||
# report. This is useful for debugging.
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
ob_start();
|
||||
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/cronjobs.php");
|
||||
$schedule = Cache::get("cron_schedule");
|
||||
if ($schedule == null)
|
||||
|
@ -14,6 +14,7 @@ use okapi\ParamMissing;
|
||||
use okapi\InvalidParam;
|
||||
use okapi\OkapiServiceRunner;
|
||||
use okapi\OkapiInternalRequest;
|
||||
use okapi\BadRequest;
|
||||
|
||||
class View
|
||||
{
|
||||
@ -22,22 +23,22 @@ class View
|
||||
# This is a hidden page for OKAPI developers. It will output a complete
|
||||
# structure of the database. This is useful for making OKAPI compatible
|
||||
# across different OC installations.
|
||||
|
||||
|
||||
$user = Settings::get('DB_USERNAME');
|
||||
$password = Settings::get('DB_PASSWORD');
|
||||
$dbname = Settings::get('DB_NAME');
|
||||
$struct = shell_exec("mysqldump --no-data -u$user -p$password $dbname");
|
||||
|
||||
|
||||
# Remove the "AUTO_INCREMENT=..." values. They break the diffs.
|
||||
|
||||
|
||||
$struct = preg_replace("/ AUTO_INCREMENT=([0-9]+)/i", "", $struct);
|
||||
|
||||
|
||||
# This method can be invoked with "compare_to" parameter, which points to
|
||||
# an alternate database structure (probably generated by the same script
|
||||
# in other OKAPI instance). When invoked this way, we will attempt to
|
||||
# generate SQL script which alters LOCAL database is such a way that it
|
||||
# will become THE OTHER database.
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
if (isset($_GET['compare_to']))
|
||||
@ -45,7 +46,11 @@ class View
|
||||
$scheme = parse_url($_GET['compare_to'], PHP_URL_SCHEME);
|
||||
if (in_array($scheme, array('http', 'https')))
|
||||
{
|
||||
$alternate_struct = @file_get_contents($_GET['compare_to']);
|
||||
try {
|
||||
$alternate_struct = @file_get_contents($_GET['compare_to']);
|
||||
} catch (Exception $e) {
|
||||
throw new BadRequest("Failed to load ".$_GET['compare_to']);
|
||||
}
|
||||
$response->body =
|
||||
"-- Automatically generated database diff. Use with caution!\n".
|
||||
"-- Differences obtained with help of cool library by Kirill Gerasimenko.\n\n".
|
||||
|
@ -20,25 +20,25 @@ class View
|
||||
public static function call()
|
||||
{
|
||||
# Flush the stats, so the page is fresh upon every request.
|
||||
|
||||
|
||||
require_once($GLOBALS['rootpath']."okapi/cronjobs.php");
|
||||
CronJobController::force_run("StatsWriterCronJob");
|
||||
|
||||
|
||||
# When services/caches/map/tile method is called, it writes some extra
|
||||
# stats in the okapi_stats_hourly table. This page retrieves and
|
||||
# formats these stats in a readable manner (for debugging).
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/plain; charset=utf-8";
|
||||
ob_start();
|
||||
|
||||
|
||||
$start = isset($_GET['start']) ? $_GET['start'] : date(
|
||||
"Y-m-d 00:00:00", time() - 7*86400);
|
||||
$end = isset($_GET['end']) ? $_GET['end'] : date("Y-m-d 23:59:59");
|
||||
|
||||
|
||||
print "From: $start\n";
|
||||
print " To: $end\n\n";
|
||||
|
||||
|
||||
$rs = Db::query("
|
||||
select
|
||||
service_name,
|
||||
@ -51,12 +51,12 @@ class View
|
||||
and service_name like '%caches/map/tile%'
|
||||
group by service_name
|
||||
");
|
||||
|
||||
|
||||
$total_calls = 0;
|
||||
$total_runtime = 0.0;
|
||||
$calls = array('A' => 0, 'B' => 0, 'C' => 0, 'D' => 0);
|
||||
$runtime = array('A' => 0.0, 'B' => 0.0, 'C' => 0.0, 'D' => 0.0);
|
||||
|
||||
|
||||
while (list($name, $c, $r) = mysql_fetch_array($rs))
|
||||
{
|
||||
if ($name == 'services/caches/map/tile')
|
||||
@ -76,10 +76,10 @@ class View
|
||||
print "All other will count as \"unaccounted for\".\n\n";
|
||||
$total_calls = $calls['A'];
|
||||
}
|
||||
|
||||
|
||||
$calls_left = $total_calls;
|
||||
$runtime_left = $total_runtime;
|
||||
|
||||
|
||||
$perc = function($a, $b) { return ($b > 0) ? sprintf("%.1f", 100 * $a / $b)."%" : "(?)"; };
|
||||
$avg = function($a, $b) { return ($b > 0) ? sprintf("%.4f", $a / $b)."s" : "(?)"; };
|
||||
$get_stats = function() use (&$calls_left, &$runtime_left, &$total_calls, &$total_runtime, &$perc)
|
||||
@ -89,7 +89,7 @@ class View
|
||||
str_pad($perc($runtime_left, $total_runtime), 7, " ", STR_PAD_LEFT)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
print "%CALLS %TIME Description\n";
|
||||
print "====== ====== ======================================================================\n";
|
||||
print $get_stats()." $total_calls responses served. Total runtime: ".sprintf("%.2f", $total_runtime)."s\n";
|
||||
@ -97,53 +97,53 @@ class View
|
||||
print " All of these requests needed a TileTree build/lookup. The average runtime of\n";
|
||||
print " these lookups was ".$avg($runtime['A'], $total_calls).". ".$perc($runtime['A'], $total_runtime)." of total runtime was spent here.\n";
|
||||
print "\n";
|
||||
|
||||
|
||||
$runtime_left -= $runtime['A'];
|
||||
|
||||
print $get_stats()." All calls passed here after ~".$avg($runtime['A'], $total_calls)."\n";
|
||||
|
||||
|
||||
print "\n";
|
||||
print " Lookup result was then processed and \"image description\" was created. It was\n";
|
||||
print " passed on to the TileRenderer to compute the ETag hash string. The average runtime\n";
|
||||
print " of this part was ".$avg($runtime['B'], $total_calls).". ".$perc($runtime['B'], $total_runtime)." of total runtime was spent here.\n";
|
||||
print "\n";
|
||||
|
||||
|
||||
$runtime_left -= $runtime['B'];
|
||||
|
||||
|
||||
print $get_stats()." All calls passed here after ~".$avg($runtime['A'] + $runtime['B'], $total_calls)."\n";
|
||||
|
||||
$etag_hits = $calls['B'] - $calls['C'];
|
||||
|
||||
|
||||
print "\n";
|
||||
print " $etag_hits of the requests matched the ETag and were served an HTTP 304 response.\n";
|
||||
print "\n";
|
||||
|
||||
|
||||
$calls_left = $calls['C'];
|
||||
|
||||
|
||||
print $get_stats()." $calls_left calls passed here after ~".$avg($runtime['A'] + $runtime['B'], $total_calls)."\n";
|
||||
|
||||
|
||||
$imagecache_hits = $calls['C'] - $calls['D'];
|
||||
|
||||
print "\n";
|
||||
print " $imagecache_hits of these calls hit the server image cache.\n";
|
||||
print " ".$perc($runtime['C'], $total_runtime)." of total runtime was spent to find these.\n";
|
||||
print "\n";
|
||||
|
||||
|
||||
$calls_left = $calls['D'];
|
||||
$runtime_left -= $runtime['C'];
|
||||
|
||||
|
||||
print $get_stats()." $calls_left calls passed here after ~".$avg($runtime['A'] + $runtime['B'] + $runtime['C'], $total_calls)."\n";
|
||||
print "\n";
|
||||
print " These calls required the tile to be rendered. On average, it took\n";
|
||||
print " ".$avg($runtime['D'], $calls['D'])." to *render* a tile.\n";
|
||||
print " ".$perc($runtime['D'], $total_runtime)." of total runtime was spent here.\n";
|
||||
print "\n";
|
||||
|
||||
|
||||
$runtime_left -= $runtime['D'];
|
||||
|
||||
|
||||
print $perc($runtime_left, $total_runtime)." of runtime was unaccounted for (other processing).\n";
|
||||
print "Average response time was ".$avg($total_runtime, $total_calls).".\n\n";
|
||||
|
||||
|
||||
print "Current okapi_cache score distribution:\n";
|
||||
$rs = Db::query("
|
||||
select floor(log2(score)), count(*), sum(length(value))
|
||||
@ -155,7 +155,7 @@ class View
|
||||
{
|
||||
print $count." elements ($size bytes) with score between ".pow(2, $log2)." and ".pow(2, $log2 + 1).".\n";
|
||||
}
|
||||
|
||||
|
||||
$response->body = ob_get_clean();
|
||||
return $response;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class View
|
||||
{
|
||||
require_once($GLOBALS['rootpath'].'okapi/service_runner.php');
|
||||
require_once($GLOBALS['rootpath'].'okapi/views/menu.inc.php');
|
||||
|
||||
|
||||
$vars = array(
|
||||
'menu' => OkapiMenu::get_menu_html("examples.html"),
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
@ -28,7 +28,7 @@ class View
|
||||
'okapi_rev' => Okapi::$revision,
|
||||
'site_name' => Okapi::get_normalized_site_name(),
|
||||
);
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/html; charset=utf-8";
|
||||
ob_start();
|
||||
|
@ -13,14 +13,14 @@ class View
|
||||
public static function call()
|
||||
{
|
||||
require_once('menu.inc.php');
|
||||
|
||||
|
||||
$vars = array(
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
'menu' => OkapiMenu::get_menu_html(),
|
||||
'installations' => OkapiMenu::get_installations(),
|
||||
'okapi_rev' => Okapi::$revision,
|
||||
);
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->status = "404 Not Found";
|
||||
$response->content_type = "text/html; charset=utf-8";
|
||||
|
@ -18,7 +18,7 @@ class View
|
||||
{
|
||||
# This is called when someone displays "http://../okapi/" (with no
|
||||
# html path at the end). We will redirect to the introduction page.
|
||||
|
||||
|
||||
return new OkapiRedirectResponse(Settings::get('SITE_URL').
|
||||
"okapi/introduction.html");
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class View
|
||||
{
|
||||
require_once($GLOBALS['rootpath'].'okapi/service_runner.php');
|
||||
require_once($GLOBALS['rootpath'].'okapi/views/menu.inc.php');
|
||||
|
||||
|
||||
$vars = array(
|
||||
'menu' => OkapiMenu::get_menu_html("introduction.html"),
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
@ -30,7 +30,7 @@ class View
|
||||
'installations' => OkapiMenu::get_installations(),
|
||||
'okapi_rev' => Okapi::$revision,
|
||||
);
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/html; charset=utf-8";
|
||||
ob_start();
|
||||
|
@ -18,7 +18,7 @@ class OkapiMenu
|
||||
return "<a href='".Settings::get('SITE_URL')."okapi/$link_path'".(($current_path == $link_path)
|
||||
? " class='selected'" : "").">$link_name</a><br>";
|
||||
}
|
||||
|
||||
|
||||
/** Get HTML-formatted side menu representation. */
|
||||
public static function get_menu_html($current_path = null)
|
||||
{
|
||||
@ -30,16 +30,16 @@ class OkapiMenu
|
||||
$chunks[] = self::link($current_path, "signup.html", "Sign up");
|
||||
$chunks[] = self::link($current_path, "examples.html", "Examples");
|
||||
$chunks[] = "</div>";
|
||||
|
||||
|
||||
# We need a list of all methods. We do not need their descriptions, so
|
||||
# we won't use the apiref/method_index method to get it, the static list
|
||||
# within OkapiServiceRunner will do.
|
||||
|
||||
|
||||
$methodnames = OkapiServiceRunner::$all_names;
|
||||
sort($methodnames);
|
||||
|
||||
|
||||
# We'll break them up into modules, for readability.
|
||||
|
||||
|
||||
$module_methods = array();
|
||||
foreach ($methodnames as $methodname)
|
||||
{
|
||||
@ -52,7 +52,7 @@ class OkapiMenu
|
||||
}
|
||||
$modulenames = array_keys($module_methods);
|
||||
sort($modulenames);
|
||||
|
||||
|
||||
foreach ($modulenames as $modulename)
|
||||
{
|
||||
$chunks[] = "<div class='module'>$modulename</div>";
|
||||
@ -63,7 +63,7 @@ class OkapiMenu
|
||||
}
|
||||
return implode("", $chunks);
|
||||
}
|
||||
|
||||
|
||||
public static function get_installations()
|
||||
{
|
||||
$installations = OkapiServiceRunner::call("services/apisrv/installations",
|
||||
|
@ -21,7 +21,7 @@ class View
|
||||
{
|
||||
require_once($GLOBALS['rootpath'].'okapi/service_runner.php');
|
||||
require_once($GLOBALS['rootpath'].'okapi/views/menu.inc.php');
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
$method = OkapiServiceRunner::call('services/apiref/method', new OkapiInternalRequest(
|
||||
@ -38,7 +38,7 @@ class View
|
||||
'installations' => OkapiMenu::get_installations(),
|
||||
'okapi_rev' => Okapi::$revision,
|
||||
);
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/html; charset=utf-8";
|
||||
ob_start();
|
||||
|
@ -25,7 +25,7 @@ $m = $vars['method'];
|
||||
<?= $vars['menu'] ?>
|
||||
</td>
|
||||
<td class='article'>
|
||||
|
||||
|
||||
<h1>
|
||||
<?= $m['brief_description'] ?>
|
||||
<div class='subh1'>:: <b><?= $m['name'] ?></b> method</div>
|
||||
|
@ -54,10 +54,10 @@ class View
|
||||
));
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
require_once($GLOBALS['rootpath'].'okapi/service_runner.php');
|
||||
require_once($GLOBALS['rootpath'].'okapi/views/menu.inc.php');
|
||||
|
||||
|
||||
$vars = array(
|
||||
'menu' => OkapiMenu::get_menu_html("signup.html"),
|
||||
'okapi_base_url' => Settings::get('SITE_URL')."okapi/",
|
||||
@ -69,7 +69,7 @@ class View
|
||||
? "<a href='".Settings::get('DATA_LICENSE_URL')."'>Data License</a>"
|
||||
: "Data License",
|
||||
);
|
||||
|
||||
|
||||
$response = new OkapiHttpResponse();
|
||||
$response->content_type = "text/html; charset=utf-8";
|
||||
ob_start();
|
||||
|
@ -43,12 +43,12 @@
|
||||
<?= $vars['menu'] ?>
|
||||
</td>
|
||||
<td class='article'>
|
||||
|
||||
|
||||
<h1>
|
||||
Sign up for an API Key
|
||||
<div class='subh1'>:: <b>OpenCaching API</b> Reference</div>
|
||||
</h1>
|
||||
|
||||
|
||||
<form id='signup'>
|
||||
<table cellspacing='1px' class='signup'>
|
||||
<tr>
|
||||
@ -86,7 +86,7 @@
|
||||
</form>
|
||||
|
||||
<h2>Terms of Use</h2>
|
||||
|
||||
|
||||
<p>When using data from <b><?= $vars['site_name'] ?></b> you <b>must</b> attribute the
|
||||
data back to <?= $vars['site_name'] ?>.</p>
|
||||
<ul>
|
||||
|
@ -29,16 +29,16 @@ class View
|
||||
print $str;
|
||||
flush();
|
||||
}
|
||||
|
||||
|
||||
public static function call()
|
||||
{
|
||||
# By default, this view is turned off in the urls.php file.
|
||||
# This view is for debugging TileMap performace only!
|
||||
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
|
||||
header("Content-Type: text/plain; charset=utf-8");
|
||||
|
||||
|
||||
$user_id = $_GET['u'];
|
||||
self::out("Yo. I'm $user_id.\n\n");
|
||||
|
||||
@ -64,14 +64,14 @@ class View
|
||||
$x = rand(0, (1 << $z) - 1);
|
||||
$y = rand(0, (1 << $z) - 1);
|
||||
}
|
||||
|
||||
|
||||
$tiles = array();
|
||||
for ($xx=$x; $xx<$x+4; $xx++)
|
||||
for ($yy=$y; $yy<$y+4; $yy++)
|
||||
$tiles[] = array($xx, $yy);
|
||||
srand();
|
||||
shuffle($tiles);
|
||||
|
||||
|
||||
foreach ($tiles as $tile)
|
||||
{
|
||||
list($x, $y) = $tile;
|
||||
@ -93,5 +93,5 @@ class View
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class View
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function get_max_version()
|
||||
{
|
||||
$max_db_version = 0;
|
||||
@ -50,7 +50,7 @@ class View
|
||||
}
|
||||
return $max_db_version;
|
||||
}
|
||||
|
||||
|
||||
public static function out($str)
|
||||
{
|
||||
print $str;
|
||||
@ -58,14 +58,37 @@ class View
|
||||
# Therefore, calling ob_flush would give an error.
|
||||
flush();
|
||||
}
|
||||
|
||||
|
||||
public static function call()
|
||||
{
|
||||
# First, let's acquire a lock to make sure the update isn't already running.
|
||||
# We will use one of the existing lock handles, because we don't want to use
|
||||
# to many of them. See issue 141.
|
||||
|
||||
$lock = OkapiLock::get('cronjobs-cron-5');
|
||||
$lock->acquire();
|
||||
|
||||
try
|
||||
{
|
||||
self::_call();
|
||||
$lock->release();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
# Error occured. Make sure the lock is released and rethrow.
|
||||
|
||||
$lock->release();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private static function _call()
|
||||
{
|
||||
ignore_user_abort(true);
|
||||
set_time_limit(0);
|
||||
|
||||
|
||||
header("Content-Type: text/plain; charset=utf-8");
|
||||
|
||||
|
||||
$current_ver = self::get_current_version();
|
||||
$max_ver = self::get_max_version();
|
||||
self::out("Current OKAPI database version: $current_ver\n");
|
||||
@ -84,7 +107,7 @@ class View
|
||||
else
|
||||
{
|
||||
self::out("Updating to version $max_ver... PLEASE WAIT\n\n");
|
||||
|
||||
|
||||
while ($current_ver < $max_ver)
|
||||
{
|
||||
$version_to_apply = $current_ver + 1;
|
||||
@ -101,15 +124,15 @@ class View
|
||||
}
|
||||
self::out("\nDatabase updated.\n\n");
|
||||
}
|
||||
|
||||
|
||||
self::out("Registering new cronjobs...\n");
|
||||
# Validate all cronjobs (some might have been added).
|
||||
Okapi::set_var("cron_nearest_event", 0);
|
||||
Okapi::execute_prerequest_cronjobs();
|
||||
|
||||
|
||||
self::out("\nUpdate complete.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the list of email addresses of developers who used any of the given
|
||||
* method names at least once. If $days is not null, then only consumers which
|
||||
@ -128,7 +151,7 @@ class View
|
||||
".(($days != null) ? "and sh.period_start > date_add(now(), interval -".$days." day)" : "")."
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver1()
|
||||
{
|
||||
ob_start();
|
||||
@ -153,7 +176,7 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver2()
|
||||
{
|
||||
Db::execute("
|
||||
@ -165,7 +188,7 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver3()
|
||||
{
|
||||
Db::execute("
|
||||
@ -180,7 +203,7 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver4()
|
||||
{
|
||||
Db::execute("
|
||||
@ -192,7 +215,7 @@ class View
|
||||
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver5()
|
||||
{
|
||||
Db::execute("
|
||||
@ -210,12 +233,12 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver6()
|
||||
{
|
||||
# Removed this update. It seemed dangerous to run such updates on unknown OC installations.
|
||||
}
|
||||
|
||||
|
||||
private static function ver7()
|
||||
{
|
||||
# In fact, this should be "alter cache_logs add column okapi_consumer_key...", but
|
||||
@ -231,7 +254,7 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver8()
|
||||
{
|
||||
Db::execute("
|
||||
@ -243,7 +266,7 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver9() { Db::execute("alter table okapi_consumers modify column `key` varchar(20) not null"); }
|
||||
private static function ver10() { Db::execute("alter table okapi_consumers modify column secret varchar(40) not null"); }
|
||||
private static function ver11() { Db::execute("alter table okapi_tokens modify column `key` varchar(20) not null"); }
|
||||
@ -255,7 +278,7 @@ class View
|
||||
private static function ver17() { Db::execute("alter table okapi_nonces modify column `key` varchar(255) not null"); }
|
||||
private static function ver18() { Db::execute("alter table okapi_cache_logs modify column consumer_key varchar(20) not null"); }
|
||||
private static function ver19() { Db::execute("alter table okapi_vars modify column `var` varchar(32) not null"); }
|
||||
|
||||
|
||||
private static function ver20() { Db::execute("alter table okapi_consumers modify column `key` varchar(20) collate utf8_bin not null"); }
|
||||
private static function ver21() { Db::execute("alter table okapi_consumers modify column secret varchar(40) collate utf8_bin not null"); }
|
||||
private static function ver22() { Db::execute("alter table okapi_tokens modify column `key` varchar(20) collate utf8_bin not null"); }
|
||||
@ -267,7 +290,7 @@ class View
|
||||
private static function ver28() { Db::execute("alter table okapi_nonces modify column `key` varchar(255) collate utf8_bin not null"); }
|
||||
private static function ver29() { Db::execute("alter table okapi_cache_logs modify column consumer_key varchar(20) collate utf8_bin not null"); }
|
||||
private static function ver30() { Db::execute("alter table okapi_vars modify column `var` varchar(32) collate utf8_bin not null"); }
|
||||
|
||||
|
||||
private static function ver31()
|
||||
{
|
||||
Db::execute("
|
||||
@ -281,7 +304,7 @@ class View
|
||||
) ENGINE=MEMORY DEFAULT CHARSET=utf8
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver32()
|
||||
{
|
||||
Db::execute("
|
||||
@ -298,7 +321,7 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver33()
|
||||
{
|
||||
try
|
||||
@ -310,7 +333,7 @@ class View
|
||||
// key exists
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function ver34()
|
||||
{
|
||||
Db::execute("
|
||||
@ -321,7 +344,7 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver35()
|
||||
{
|
||||
# Inform the admin about the new cronjobs.
|
||||
@ -336,13 +359,13 @@ class View
|
||||
"Thanks, OKAPI developers."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static function ver36() { Db::execute("alter table okapi_cache modify column `key` varchar(64) not null"); }
|
||||
private static function ver37() { Db::execute("delete from okapi_vars where var='last_clog_update'"); }
|
||||
private static function ver38() { Db::execute("alter table okapi_clog modify column data mediumblob"); }
|
||||
private static function ver39() { Db::execute("delete from okapi_clog"); }
|
||||
private static function ver40() { Db::execute("alter table okapi_cache modify column value mediumblob"); }
|
||||
|
||||
|
||||
private static function ver41()
|
||||
{
|
||||
# Force changelog reset (will be produced one day back)
|
||||
@ -352,9 +375,9 @@ class View
|
||||
Okapi::set_var("cron_nearest_event", 0);
|
||||
Cache::delete('cron_schedule');
|
||||
}
|
||||
|
||||
|
||||
private static function ver42() { Db::execute("delete from okapi_cache where length(value) = 65535"); }
|
||||
|
||||
|
||||
private static function ver43()
|
||||
{
|
||||
$emails = self::get_consumers_of(array('services/replicate/changelog', 'services/replicate/fulldump'), 14);
|
||||
@ -371,11 +394,11 @@ class View
|
||||
print "OKAPI Team";
|
||||
Okapi::mail_from_okapi($emails, "A change in the 'replicate' module.", ob_get_clean());
|
||||
}
|
||||
|
||||
|
||||
private static function ver44() { Db::execute("alter table caches add column okapi_syncbase timestamp not null after last_modified;"); }
|
||||
private static function ver45() { Db::execute("update caches set okapi_syncbase=last_modified;"); }
|
||||
private static function ver46() { /* no longer necessary */ }
|
||||
|
||||
|
||||
private static function ver47()
|
||||
{
|
||||
Db::execute("
|
||||
@ -388,7 +411,7 @@ class View
|
||||
);
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver48()
|
||||
{
|
||||
ob_start();
|
||||
@ -401,7 +424,7 @@ class View
|
||||
print "OKAPI Team";
|
||||
Okapi::mail_admins("Database modification notice: caches.okapi_syncbase", ob_get_clean());
|
||||
}
|
||||
|
||||
|
||||
private static function print_common_db_alteration_info()
|
||||
{
|
||||
print "-- About OKAPI's database modifications --\n\n";
|
||||
@ -414,27 +437,27 @@ class View
|
||||
print "(outside of the \"okapi_\" table-scope). If you have any comments\n";
|
||||
print "on this procedure, please submit them to our issue tracker.\n\n";
|
||||
}
|
||||
|
||||
|
||||
private static function ver49() { Db::execute("alter table caches add key okapi_syncbase (okapi_syncbase);"); }
|
||||
private static function ver50() { /* no longer necessary */ }
|
||||
|
||||
|
||||
private static function ver51()
|
||||
{
|
||||
# Before revision 417, OKAPI used to make the following change:
|
||||
# - Db::execute("alter table cache_logs modify column last_modified timestamp not null;");
|
||||
# It doesn't do that anymore. Instead, it adds a separate column for itself (okapi_syncbase).
|
||||
}
|
||||
|
||||
|
||||
private static function ver52()
|
||||
{
|
||||
# Before revision 417, OKAPI used to make the following change (on OCDE branch):
|
||||
# - Db::execute("alter table cache_logs_archived modify column last_modified timestamp not null;");
|
||||
# It doesn't do that anymore. Instead, it adds a separate column for itself (okapi_syncbase).
|
||||
}
|
||||
|
||||
|
||||
private static function ver53() { Db::execute("alter table cache_logs add column okapi_syncbase timestamp not null after last_modified;"); }
|
||||
private static function ver54() { Db::execute("update cache_logs set okapi_syncbase=last_modified;"); }
|
||||
|
||||
|
||||
private static function ver55()
|
||||
{
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
@ -444,7 +467,7 @@ class View
|
||||
}
|
||||
Db::execute("alter table cache_logs_archived add column okapi_syncbase timestamp not null after last_modified;");
|
||||
}
|
||||
|
||||
|
||||
private static function ver56()
|
||||
{
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
@ -454,7 +477,7 @@ class View
|
||||
}
|
||||
Db::execute("update cache_logs_archived set okapi_syncbase=last_modified;");
|
||||
}
|
||||
|
||||
|
||||
private static function ver57()
|
||||
{
|
||||
ob_start();
|
||||
@ -467,7 +490,7 @@ class View
|
||||
print "OKAPI Team";
|
||||
Okapi::mail_admins("Database modification notice: caches.okapi_syncbase", ob_get_clean());
|
||||
}
|
||||
|
||||
|
||||
private static function ver58()
|
||||
{
|
||||
#
|
||||
@ -521,9 +544,9 @@ class View
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function ver61() { Db::execute("alter table cache_logs add key okapi_syncbase (okapi_syncbase);"); }
|
||||
|
||||
|
||||
private static function ver62()
|
||||
{
|
||||
if (Settings::get('OC_BRANCH') == 'oc.pl')
|
||||
@ -533,7 +556,7 @@ class View
|
||||
}
|
||||
Db::execute("alter table cache_logs_archived add key okapi_syncbase (okapi_syncbase);");
|
||||
}
|
||||
|
||||
|
||||
private static function ver63()
|
||||
{
|
||||
Db::execute("
|
||||
@ -546,7 +569,7 @@ class View
|
||||
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver64()
|
||||
{
|
||||
Db::execute("
|
||||
@ -565,14 +588,14 @@ class View
|
||||
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver65() { Db::execute("alter table okapi_tile_status engine=innodb;"); }
|
||||
private static function ver66() { Db::execute("alter table okapi_tile_caches engine=innodb;"); }
|
||||
|
||||
|
||||
private static function ver67()
|
||||
{
|
||||
# Remove unused locks (these might have been created in previous versions of OKAPI).
|
||||
|
||||
|
||||
for ($z=0; $z<=2; $z++)
|
||||
for ($x=0; $x<(1<<$z); $x++)
|
||||
for ($y=0; $y<(1<<$z); $y++)
|
||||
@ -582,11 +605,11 @@ class View
|
||||
OkapiLock::get($lockname)->remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function ver68()
|
||||
{
|
||||
# Once again, remove unused locks.
|
||||
|
||||
|
||||
for ($z=0; $z<=21; $z++)
|
||||
{
|
||||
foreach (array("", "-0", "-1") as $suffix)
|
||||
@ -597,16 +620,16 @@ class View
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static function ver69()
|
||||
{
|
||||
# TileTree border margins changed. We need to recalculate all nodes
|
||||
# but the root.
|
||||
|
||||
|
||||
Db::execute("delete from okapi_tile_caches where z > 0");
|
||||
Db::execute("delete from okapi_tile_status where z > 0");
|
||||
}
|
||||
|
||||
|
||||
private static function ver70()
|
||||
{
|
||||
Db::execute("
|
||||
@ -615,14 +638,14 @@ class View
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
private static function ver71() { Db::execute("alter table okapi_cache add column score float(4,2) default null after `key`"); }
|
||||
private static function ver72() { Db::execute("alter table okapi_cache change column expires expires datetime after score"); }
|
||||
private static function ver73() { Db::execute("update okapi_cache set score=1, expires=date_add(now(), interval 360 day) where `key` like 'tile/%'"); }
|
||||
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("
|
||||
@ -645,9 +668,10 @@ class View
|
||||
) 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"); }
|
||||
private static function ver83() { Db::execute("alter table okapi_stats_temp engine=InnoDB"); }
|
||||
}
|
||||
|
Reference in New Issue
Block a user