You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
5.5 KiB

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Laravel\Lumen\Routing\Controller as BaseController;
  4. use Illuminate\Http\Request;
  5. use DB;
  6. use Quartz;
  7. use Log;
  8. use DateTime, DateTimeZone;
  9. use App\Jobs\TripComplete;
  10. class Api extends BaseController
  11. {
  12. public function account(Request $request) {
  13. $token = $request->input('token');
  14. if(!$token)
  15. return response(json_encode(['error' => 'no token provided']))->header('Content-Type', 'application/json');
  16. $db = DB::table('databases')->where('write_token','=',$token)->first();
  17. if(!$db)
  18. return response(json_encode(['error' => 'invalid token']))->header('Content-Type', 'application/json');
  19. return response(json_encode(['name' => $db->name]))->header('Content-Type', 'application/json');
  20. }
  21. public function query(Request $request) {
  22. $token = $request->input('token');
  23. if(!$token)
  24. return response(json_encode(['error' => 'no token provided']))->header('Content-Type', 'application/json');
  25. $db = DB::table('databases')->where('read_token','=',$token)->first();
  26. if(!$db)
  27. return response(json_encode(['error' => 'invalid token']))->header('Content-Type', 'application/json');
  28. $qz = new Quartz\DB(env('STORAGE_DIR').$db->name, 'r');
  29. if($request->input('tz')) {
  30. $tz = $request->input('tz');
  31. } else {
  32. $tz = 'UTC';
  33. }
  34. if($date=$request->input('date')) {
  35. $start = DateTime::createFromFormat('Y-m-d H:i:s', $date.' 00:00:00', new DateTimeZone($tz));
  36. $end = DateTime::createFromFormat('Y-m-d H:i:s', $date.' 23:59:59', new DateTimeZone($tz));
  37. } else {
  38. return response(json_encode(['error' => 'no date provided']))->header('Content-Type', 'application/json');
  39. }
  40. $results = $qz->queryRange($start, $end);
  41. $locations = [];
  42. $properties = [];
  43. $events = [];
  44. if($request->input('format') == 'linestring') {
  45. foreach($results as $id=>$record) {
  46. // When returning a linestring, separate out the "event" records from the "location" records
  47. if(property_exists($record->data->properties, 'action')) {
  48. $rec = $record->data;
  49. # add a unixtime property
  50. $rec->properties->unixtime = (int)$record->date->format('U');
  51. $events[] = $rec;
  52. } else {
  53. #$record->date->format('U.u');
  54. $locations[] = $record->data;
  55. $props = $record->data->properties;
  56. $date = $record->date;
  57. $date->setTimeZone(new DateTimeZone($tz));
  58. $props->timestamp = $date->format('c');
  59. $props->unixtime = (int)$date->format('U');
  60. $properties[] = $props;
  61. }
  62. }
  63. $linestring = array(
  64. 'type' => 'LineString',
  65. 'coordinates' => [],
  66. 'properties' => $properties
  67. );
  68. foreach($locations as $loc) {
  69. if(property_exists($loc, 'geometry'))
  70. $linestring['coordinates'][] = $loc->geometry->coordinates;
  71. else
  72. $linestring['coordinates'][] = null;
  73. }
  74. $response = array(
  75. 'linestring' => $linestring,
  76. 'events' => $events
  77. );
  78. } else {
  79. foreach($results as $id=>$record) {
  80. $locations[] = $record->data;
  81. }
  82. $response = [
  83. 'locations' => $locations
  84. ];
  85. }
  86. return response(json_encode($response))->header('Content-Type', 'application/json');
  87. }
  88. public function input(Request $request) {
  89. $token = $request->input('token');
  90. if(!$token)
  91. return response(json_encode(['error' => 'no token provided']))->header('Content-Type', 'application/json');
  92. $db = DB::table('databases')->where('write_token','=',$token)->first();
  93. if(!$db)
  94. return response(json_encode(['error' => 'invalid token']))->header('Content-Type', 'application/json');
  95. if(!is_array($request->input('locations')))
  96. return response(json_encode(['error' => 'invalid input', 'error_description' => 'parameter "locations" must be an array of GeoJSON data with a "timestamp" property']))->header('Content-Type', 'application/json');
  97. $qz = new Quartz\DB(env('STORAGE_DIR').$db->name, 'w');
  98. $num = 0;
  99. $trips = 0;
  100. foreach($request->input('locations') as $loc) {
  101. if(array_key_exists('properties', $loc)) {
  102. if(array_key_exists('timestamp', $loc['properties'])) {
  103. try {
  104. if(preg_match('/^\d+\.\d+$/', $loc['properties']['timestamp']))
  105. $date = DateTime::createFromFormat('U.u', $loc['properties']['timestamp']);
  106. elseif(preg_match('/^\d+$/', $loc['properties']['timestamp']))
  107. $date = DateTime::createFromFormat('U', $loc['properties']['timestamp']);
  108. else
  109. $date = new DateTime($loc['properties']['timestamp']);
  110. if($date) {
  111. $num++;
  112. $qz->add($date, $loc);
  113. if(array_key_exists('type', $loc['properties']) && $loc['properties']['type'] == 'trip') {
  114. try {
  115. $job = (new TripComplete($db->id, $loc))->onQueue('compass');
  116. $this->dispatch($job);
  117. $trips++;
  118. } catch(Exception $e) {
  119. Log::warning('Received invalid trip');
  120. }
  121. }
  122. } else {
  123. Log::warning('Received invalid date: ' . $loc['properties']['timestamp']);
  124. }
  125. } catch(Exception $e) {
  126. Log::warning('Received invalid date: ' . $loc['properties']['timestamp']);
  127. }
  128. }
  129. }
  130. }
  131. return response(json_encode(['result' => 'ok', 'saved' => $num, 'trips' => $trips]))->header('Content-Type', 'application/json');
  132. }
  133. }