forked from opencaching/okapi
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
issue opencaching#601 upload fieldnotes
- Loading branch information
Showing
3 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
okapi/services/draftlogs/upload_fieldnotes_file/WebService.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
<?php | ||
|
||
namespace okapi\services\draftlogs\upload_fieldnotes_file; | ||
|
||
use okapi\core\Exception\InvalidParam; | ||
use okapi\core\Exception\ParamMissing; | ||
use okapi\core\Db; | ||
use okapi\core\Okapi; | ||
use okapi\core\OkapiServiceRunner; | ||
use okapi\core\Request\OkapiInternalRequest; | ||
use okapi\core\Request\OkapiRequest; | ||
use okapi\services\logs\LogsCommon; | ||
use okapi\Settings; | ||
|
||
class WebService | ||
{ | ||
public static function options() | ||
{ | ||
return array( | ||
'min_auth_level' => 3 | ||
); | ||
} | ||
|
||
public static function call(OkapiRequest $request) | ||
{ | ||
if (Settings::get('OC_BRANCH') != 'oc.de') | ||
throw new BadRequest('This method is not supported in this OKAPI installation. See the has_draftlogs field in services/apisrv/installation method.'); | ||
|
||
$field_notes = $request->get_parameter('field_notes'); | ||
if (!$field_notes) throw new ParamMissing('field_notes'); | ||
|
||
$notes = self::parse_notes($field_notes); | ||
|
||
foreach ($notes['records'] as $n) | ||
{ | ||
$geocache = OkapiServiceRunner::call( | ||
'services/caches/geocache', | ||
new OkapiInternalRequest($request->consumer, $request->token, array( | ||
'cache_code' => $n['code'], | ||
'fields' => 'internal_id' | ||
)) | ||
); | ||
|
||
try { | ||
$type = Okapi::logtypename2id($n['type']); | ||
} catch (\Exception $e) { | ||
throw new InvalidParam('Type', 'Invalid log type provided.'); | ||
} | ||
|
||
$dateString = strtotime($n['date']); | ||
if ($dateString === false) { | ||
throw new InvalidParam('`Date` field in log record', "Input data not recognized."); | ||
} else { | ||
$date = date("Y-m-d H:i:s", $dateString); | ||
} | ||
|
||
$user_id = $request->token->user_id; | ||
$geocache_id = $geocache['internal_id']; | ||
$text = $n['log']; | ||
|
||
Db::query(" | ||
insert into field_note ( | ||
user_id, geocache_id, type, date, text | ||
) values ( | ||
'".Db::escape_string($user_id)."', | ||
'".Db::escape_string($geocache_id)."', | ||
'".Db::escape_string($type)."', | ||
'".Db::escape_string($date)."', | ||
'".Db::escape_string($text)."' | ||
) | ||
"); | ||
|
||
} | ||
$result = array( | ||
'success' => true, | ||
'totalRecords' => $notes['totalRecords'], | ||
'processedRecords' => $notes['processedRecords'] | ||
); | ||
return Okapi::formatted_response($request, $result); | ||
} | ||
|
||
// ------------------------------------------------------------------ | ||
|
||
private static function parse_notes($field_notes) | ||
{ | ||
$decoded_field_notes = base64_decode($field_notes, true); | ||
if ($decoded_field_notes === false) throw new InvalidParam('field_notes', "Input data is not properly base64 encoded."); | ||
|
||
$multiline = self::fieldNotesTxtArea2Array($decoded_field_notes); | ||
$submittable_logtype_names = Okapi::get_submittable_logtype_names(); | ||
$records = []; | ||
$totalRecords = 0; | ||
$processedRecords = 0; | ||
|
||
foreach ($multiline as $line) { | ||
$totalRecords++; | ||
$line = trim($line); | ||
$fields = str_getcsv($line); | ||
|
||
$code = $fields[0]; | ||
$date = $fields[1]; | ||
$type = $fields[2]; | ||
|
||
if (!in_array($type, $submittable_logtype_names)) continue; | ||
|
||
$log = nl2br($fields[3]); | ||
|
||
$records[] = [ | ||
'code' => $code, | ||
'date' => $date, | ||
'type' => $type, | ||
'log' => $log, | ||
]; | ||
$processedRecords++; | ||
} | ||
return ['success' => true, 'records' => $records, 'totalRecords' => $totalRecords, 'processedRecords' => $processedRecords]; | ||
} | ||
|
||
|
||
// ------------------------------------------------------------------ | ||
|
||
private static function fieldNotesTxtArea2Array($fieldnotes) | ||
{ | ||
$output = []; | ||
$buffer = ''; | ||
$start = true; | ||
|
||
$lines = explode("\n", $fieldnotes); | ||
$lines = array_filter($lines); // Drop empty lines | ||
|
||
foreach ($lines as $line) { | ||
if ($start) { | ||
$buffer = $line; | ||
$start = false; | ||
} else { | ||
if (strpos($line, 'OC') !== 0) { | ||
$buffer .= "\n" . $line; | ||
} else { | ||
$output[] = trim($buffer); | ||
$buffer = $line; | ||
} | ||
} | ||
} | ||
|
||
if (!$start) { | ||
$output[] = trim($buffer); | ||
} | ||
|
||
return $output; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<xml> | ||
<brief>Upload Fieldnotes</brief> | ||
<issue-id>630</issue-id> | ||
<desc> | ||
<p>Upload a set of one or more fieldnotes records.</p> | ||
</desc> | ||
<req name='field_notes' infotags='ocde-specific'> | ||
<p>This method allows you to upload a series of fieldnotes in the CSV format. | ||
Fieldnotes are draft versions of log entries. Once uploaded, users will be able | ||
to review, edit, and submit them via the Opencaching site.</p> | ||
|
||
<p>Fieldnotes do not have a CSV header in the file that might describe the columns.</p> | ||
<p>Each record describes a geocache log consisting of four fields:</p> | ||
<ol> | ||
<li>Geocache Code</li> | ||
<li>Date</li> | ||
<li>Log Type</li> | ||
<li>Log Text</li> | ||
</ol> | ||
<p>The first three fields are string entities that don't have line control characters in them, | ||
the Log Text field is different and a bit difficult as it may spread over muliple lines | ||
and it may contain quote characters. In order to preserve the structure | ||
of the records, the <i>field_notes</i> parameter must be passed as a | ||
<b>base64 encoded utf8 string</b>. UTF-16LE, UTF-16BE with or without | ||
BOM are not supported. | ||
</p> | ||
<p>The second field <i>Date</i> should be in ISO 8601 format (currently any format | ||
acceptable by PHP's strtotime function also will do, but most of them don't handle | ||
time zones properly, try to use ISO 8601!).</p> | ||
<p>Since the log type is passed as a string, its value must match the | ||
values supported by the platform (case sensitive!):</p> | ||
<pre> | ||
[ | ||
"Found it", | ||
"Didn't find it", | ||
"Comment", | ||
"Attended", | ||
"Will attend", | ||
"Archived", | ||
"Ready to search", | ||
"Temporarily unavailable" | ||
] | ||
</pre> | ||
<p>Note: This service method is not supported on all installations</p> | ||
</req> | ||
<common-format-params/> | ||
<returns> | ||
<p>A dictionary of the following structure:</p> | ||
<ul> | ||
<li>success - true</li> | ||
<li>totalRecords - number of records in <i>field_notes</i></li> | ||
<li>processedRecords - number of records inserted into the database</li> | ||
</ul> | ||
<p>processedRecords may be less than totalRecords (it may even be zero) and that | ||
is the case for the following reason: Fieldnotes files are created from | ||
Geocaching client applications on Smartphones. These applications support multiple | ||
geocaching platforms from which opencaching is only one of them. Conseqently the | ||
Fieldnotes file is a "hybrid file" which contains records for multiple different | ||
platforms. For instance for geocaching.com logs, the records start with <b>GC....</b> | ||
while on opencaching.de the log records start with <b>OC....</b>. Other opencaching | ||
platforms use other codes, for instance opencaching.pl uses <b>OP...</b>.</p> | ||
<p> | ||
The client application uploads one and the same Fielnotes file to all platforms and it is the platform's | ||
task to filter out what matches their objects. Geocaching.com will discard "OC logs" | ||
and opencaching.de discards everything that doesn't start with "OC."</p> | ||
|
||
<p>In addition, in that hybrid file there will be <i>Log Type</i>, a string that | ||
inevitably has a different definition for the various platforms. For instance, what | ||
is called a "Write note" log on geocaching.com is recognized as "Comments" on | ||
opencaching platforms. Consequently fieldnotes records which have a Log Type which | ||
is not understood by the opencaching platform will be discarded without notice.</p> | ||
<p>It is the responsibility of the client application to assign the correct Log Type | ||
string when the offline log is created.</p> | ||
</returns> | ||
</xml> |