Skip to content

issue#627 listservices: Full suite of managing geocache lists via OKAPI services #631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions okapi/core/OkapiServiceRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ class OkapiServiceRunner
'services/caches/formatters/garmin',
'services/caches/formatters/ggz',
'services/caches/map/tile',
'services/lists/add_caches',
'services/lists/create',
'services/lists/delete',
'services/lists/get_caches',
'services/lists/remove_caches',
'services/lists/query',
'services/lists/update',
'services/logs/capabilities',
'services/logs/delete',
'services/logs/edit',
Expand Down
67 changes: 67 additions & 0 deletions okapi/services/lists/add_caches/WebService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace okapi\services\lists\add_caches;

use okapi\core\Db;
use okapi\core\Okapi;
use okapi\core\Request\OkapiRequest;
use okapi\Settings;
use okapi\core\Exception\InvalidParam;

class WebService
{
public static function options()
{
return array(
'min_auth_level' => 3
);
}

public static function call(OkapiRequest $request)
{
$result = array(
'success' => false
);

$user_id = $request->token->user_id;

$listId = $request->get_parameter('list_id');
$cacheCodes = $request->get_parameter('cache_codes');

if (empty($listId)) {
throw new InvalidParam('list_id', 'list_id is mandatory and must not be empty.');
}

if (empty($cacheCodes)) {
throw new InvalidParam('cache_codes', 'cache_codes is mandatory and must not be empty.');
}

$cacheCodesArray = array_unique(explode('|', $cacheCodes));

// Check the length
if (count($cacheCodesArray) > 500) {
throw new InvalidParam('cache_codes', 'The number of cache codes exceeds the limit of 500.');
}

// Escape cache codes and build the SQL query
$escapedCacheCodes = implode("','", array_map('\okapi\core\Db::escape_string', $cacheCodesArray));

// Fetch cache_ids from the caches table using INSERT IGNORE
$rs = Db::query("
INSERT IGNORE INTO cache_list_items (cache_list_id, cache_id)
SELECT '$listId', cache_id
FROM caches
WHERE wp_oc IN ('$escapedCacheCodes')
");

$insertedCount = $rs->rowCount(); // Get the number of affected rows

$result = array(
'success' => true,
'added_count' => $insertedCount
);

return Okapi::formatted_response($request, $result);
}
}

23 changes: 23 additions & 0 deletions okapi/services/lists/add_caches/docs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<xml>
<brief>Add Caches To List</brief>
<issue-id>627</issue-id>
<desc>
<p>This method is used to add geocaches to an existing list.</p>
</desc>
<req name="list_id">
<p>The id of a list. List IDs can be obtained by ::service/lists/query</p>
</req>
<req name="cache_codes">
<p>A pipe separated list of cache_codes to be added to the list.</p>
<p>Up to 500 geoaches can be added to the list by one request to
this method</p>
</req>
<common-format-params/>
<returns>
<p>A dictionary of the following structure:</p>
<ul>
<li>success - true</li>
<li>added_count - number of geocaches added to the list</li>
</ul>
</returns>
</xml>
93 changes: 93 additions & 0 deletions okapi/services/lists/create/WebService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

namespace okapi\services\lists\create;

use okapi\core\Db;
use okapi\core\Okapi;
use okapi\core\Request\OkapiRequest;
use okapi\Settings;
use okapi\core\Exception\InvalidParam;

class WebService
{

public static function options()
{
return array(
'min_auth_level' => 3
);
}

public static function call(OkapiRequest $request)
{
$result = array(
'success' => false
);

if (Settings::get('OC_BRANCH') == 'oc.de')
{
$user_id = $request->token->user_id;

$listName = $request->get_parameter('list_name');
$listDescription = $request->get_parameter('list_description');
$listStatus = $request->get_parameter('list_status');
$isWatched = $request->get_parameter('is_watched');
$listPassword = $request->get_parameter('list_password');

if (empty($listName)) {
throw new InvalidParam('list_name', 'list_name is mandatory and must not be empty.');
}

$insertFields = array(
'name' => Db::escape_string($listName),
'user_id' => Db::escape_string($user_id)
);

if (!empty($listDescription)) {
$insertFields['description'] = Db::escape_string($listDescription);
}

if ($listStatus !== null && $listStatus !== '') {
$listStatus = (int)$listStatus;
if (!in_array($listStatus, [0, 2, 3])) {
throw new InvalidParam('list_status', 'list_status must be a valid value (0, 2, 3).');
}
$insertFields['is_public'] = $listStatus;

// Handle list_password only if list_status is 0 (private)
if ($listStatus == 0) {
if (isset($listPassword) && $listPassword !== '') {
$insertFields['password'] = substr(Db::escape_string($listPassword), 0, 16);
}
}
}

$columns = implode(', ', array_keys($insertFields));
$values = "'" . implode("', '", $insertFields) . "'";

$insertQuery = "INSERT INTO cache_lists ($columns) VALUES ($values)";
Db::query($insertQuery);

$listId = Db::last_insert_id();

// Handle is_watched
if ($isWatched !== null && $isWatched !== '') {
$isWatched = (int)$isWatched;
if (!in_array($isWatched, [0, 1])) {
throw new InvalidParam('is_watched', 'is_watched must be a valid value (0, 1).');
}

// Insert a new record
Db::query("INSERT INTO cache_list_watches (cache_list_id, user_id, is_watched) VALUES (LAST_INSERT_ID(), '$user_id', $isWatched)");
}

$result = array(
'success' => true,
'message' => 'Cache list created successfully.',
'list_id' => $listId
);
}
return Okapi::formatted_response($request, $result);
}
}

46 changes: 46 additions & 0 deletions okapi/services/lists/create/docs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<xml>
<brief>Create Cache List</brief>
<issue-id>627</issue-id>
<desc>
<p>This method creates a list for adding geocaches to. Only the list is created,
no geocaches are added to it during the create. For adding and removing geocaches
to/from the list use specific methods within the ::services/lists namespace
</p>
</desc>
<req name="list_name">
<p>A string, defining the human readable name of the list</p>
</req>
<opt name="list_description">
<p>A string via which a description of the list's purpose and
potentially content can be defined.</p>
</opt>
<opt name="list_status">
<p>This parameter can take the following values:
<ul>
<li><b>0</b> - The list is private</li>
<li><b>2</b> - The list is public</li>
<li><b>3</b> - The list is public and is visible in cache listings</li>
</ul>
</p>
</opt>
<opt name="list_password">
<p>This parameter allows to add a password to a private list. The password
has no meaning if the list is public. The first 16 alphanumeric characters
are used as a password. No encryption is performed in the password, instead
it is stored in the database in plain text.</p>
</opt>
<opt name="list_watch">
<p>A boolean, either 0, 1, false, true. If set to 1 or true
a user wants to get a notification if the content of the list
changes.</p>
</opt>
<common-format-params/>
<returns>
<p>A dictionary of the following structure:</p>
<ul>
<li>success - true</li>
<li>message - Cache list created successfully</li>
<li>list_id - The id of the list by which it can be referenced</li>
</ul>
</returns>
</xml>
57 changes: 57 additions & 0 deletions okapi/services/lists/delete/WebService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace okapi\services\lists\delete;

use okapi\core\Db;
use okapi\core\Okapi;
use okapi\core\Request\OkapiRequest;
use okapi\Settings;
use okapi\core\Exception\InvalidParam;

class WebService
{

public static function options()
{
return array(
'min_auth_level' => 3
);
}

public static function call(OkapiRequest $request)
{
$result = array(
'success' => false
);

if (Settings::get('OC_BRANCH') == 'oc.de')
{
$user_id = $request->token->user_id;

$listId = $request->get_parameter('list_id');

if (empty($listId) || !is_numeric($listId)) {
throw new InvalidParam('list_id', 'list_id is mandatory and must be numeric.');
}

// Check if the list exists
$countQuery = Db::query("SELECT COUNT(*) AS count FROM cache_lists WHERE id = '$listId' AND user_id = '$user_id'");
$listExists = Db::fetch_assoc($countQuery)['count'];
if ($listExists == 0) {
throw new InvalidParam('list_id', 'The specified list does not exist.');
}

// Proceed with the deletion process
Db::query("DELETE FROM cache_lists WHERE id = '$listId'");
Db::query("DELETE FROM cache_list_watches WHERE cache_list_id = '$listId'");
Db::query("DELETE FROM cache_list_items WHERE cache_list_id = '$listId'");

$result = array(
'success' => true,
'message' => 'Cache list deleted successfully.'
);
}
return Okapi::formatted_response($request, $result);
}
}

20 changes: 20 additions & 0 deletions okapi/services/lists/delete/docs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<xml>
<brief>Delete Cache List</brief>
<issue-id>627</issue-id>
<desc>
<p>This method is used to delete a geocache list. The geocache objects
that were on the list will not be touched in any way.</p>
</desc>
<req name="list_id">
<p>The id of the list to be removed. IDs can be obtained by
the service ::services/lists/query</p>
</req>
<common-format-params/>
<returns>
<p>A dictionary of the following structure:</p>
<ul>
<li>success - true</li>
<li>message - cache list deleted successfully</li>
</ul>
</returns>
</xml>
61 changes: 61 additions & 0 deletions okapi/services/lists/get_caches/WebService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace okapi\services\lists\get_caches;

use okapi\core\Db;
use okapi\core\Okapi;
use okapi\core\Request\OkapiRequest;
use okapi\Settings;
use okapi\core\Exception\InvalidParam;

class WebService
{
public static function options()
{
return array(
'min_auth_level' => 3
);
}

public static function call(OkapiRequest $request)
{
$result = array(
'success' => false
);

$user_id = $request->token->user_id;
$listId = $request->get_parameter('list_id');

if (empty($listId)) {
throw new InvalidParam('list_id', 'list_id is mandatory and must not be empty.');
}

// Fetch cache_ids associated with the specified list
$cacheIdsArray = Db::select_column("
SELECT cache_id
FROM cache_list_items
WHERE cache_list_id = '$listId'
");

$cacheCount = count($cacheIdsArray);

// Fetch cache_codes based on cache_ids
$cacheCodesArray = array();

if (!empty($cacheIdsArray)) {
$cacheIds = implode(',', $cacheIdsArray);
$cacheCodesArray = Db::select_column(
"SELECT wp_oc FROM caches WHERE cache_id IN ($cacheIds)"
);
}

$result = array(
'success' => true,
'cache_codes' => implode('|', $cacheCodesArray),
'cache_count' => $cacheCount
);

return Okapi::formatted_response($request, $result);
}
}

Loading