diff --git a/app/Console/Commands/MqttSub.php b/app/Console/Commands/MqttSub.php index 6781ac1..5167d0a 100644 --- a/app/Console/Commands/MqttSub.php +++ b/app/Console/Commands/MqttSub.php @@ -6,6 +6,7 @@ use Illuminate\Console\Command; use PhpMqtt\Client\Facades\MQTT; use App\Http\Controllers\LockerController; +use App\Models\OfflineSyncLog; class mqttSub extends Command { @@ -47,6 +48,34 @@ public function handle() list($lockerEncoding, $error) = explode(",", $message, 2); DB::table("lockers")->where('lockerEncoding', $lockerEncoding)->update(['error' => (int)$error]); }, 0); + $mqtt->subscribe('locker/offline', function (string $topic, string $message) { + echo sprintf("Received QoS level 0 message on topic [%s]: \r\n%s\r\n", $topic, $message); + list($mode, $error) = explode(",", $message, 2); + switch ($mode) { + case 'auto': + OfflineSyncLog::create([ + 'mode' => $mode, + 'error' => (int)$error, + ]); + break; + case 'manual': + $log = OfflineSyncLog::where(['mode' => $mode, 'error' => null]) + ->orderBy('created_at', 'desc') + ->first(); + if ($log) { + $log->update(['error' => (int)$error]); + OfflineSyncLog::where(['mode' => $mode, 'error' => null])->update(['error' => 1]); + } else { + OfflineSyncLog::create([ + 'mode' => $mode, + 'error' => (int)$error, + ]); + } + break; + default: + break; + } + }, 0); $mqtt->loop(true); } catch (\Exception $e) { echo sprintf($e->getMessage()); diff --git a/app/Http/Controllers/LockerController.php b/app/Http/Controllers/LockerController.php index 978e560..85a7413 100644 --- a/app/Http/Controllers/LockerController.php +++ b/app/Http/Controllers/LockerController.php @@ -164,6 +164,30 @@ public function RPIunlock(Request $request) return response()->json($response, $httpstatus); } + /** + * Display a listing of the resource. + * + * @OA\Get( + * tags={"Locker"}, + * path="/api/RPIList", + * security={{"sanctum":{}}}, + * @OA\Response(response=200, description="OK", @OA\JsonContent()), + * ) + * + * @return AnonymousResourceCollection + */ + public function RPIList() + { + $locker = Locker::with('User:id,cardId') + ->orderBy('id', 'asc') + ->get(['id', 'lockerNo', 'lockerEncoding', 'userId']) + ->map(function ($item) { + return Arr::except($item, ['userId']); + }); + return response()->json($locker, 200); + } + + /** * Display a listing of the resource. * diff --git a/app/Http/Controllers/OfflineDataController.php b/app/Http/Controllers/OfflineDataController.php new file mode 100644 index 0000000..576d699 --- /dev/null +++ b/app/Http/Controllers/OfflineDataController.php @@ -0,0 +1,85 @@ +get(); + return response()->json(OfflineSyncLogResource::collection($offlineSyncLogs), 200); + } + /** + * Request Sync + * + * @return \Illuminate\Http\Response + */ + public function requestSync(Request $request) + { + $token = $request->header('token'); + $user = User::where('remember_token', '=', $token)->first(); + $user->OfflineSyncLog()->create(['mode' => 'manual']); + + $mqtt = MQTT::connection(); + $mqtt->publish('locker/offline', 'sync', 0); + $mqtt->loop(true, true); + + return response()->json(['message' => 'Sync request sent'], 200); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + // + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + // + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + // + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy($id) + { + // + } +} diff --git a/app/Http/Resources/OfflineSyncLogResource.php b/app/Http/Resources/OfflineSyncLogResource.php new file mode 100644 index 0000000..9db5968 --- /dev/null +++ b/app/Http/Resources/OfflineSyncLogResource.php @@ -0,0 +1,25 @@ + $this->id, + 'time' => $this->created_at, + 'mode' => $this->mode, + 'error' => $this->error, + 'user' => $this->user, + ]; + } +} diff --git a/app/Models/OfflineSyncLog.php b/app/Models/OfflineSyncLog.php new file mode 100644 index 0000000..4414c12 --- /dev/null +++ b/app/Models/OfflineSyncLog.php @@ -0,0 +1,22 @@ +belongsTo(User::class, 'userId', 'id'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index d045f7d..4514fff 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -70,4 +70,9 @@ public function Record() { return $this->hasMany(Record::class, 'userId', 'id'); } + + public function OfflineSyncLog() + { + return $this->hasMany(OfflineSyncLog::class, 'userId', 'id'); + } } diff --git a/database/migrations/2023_05_04_130921_create_offline_sync_logs_table.php b/database/migrations/2023_05_04_130921_create_offline_sync_logs_table.php new file mode 100644 index 0000000..a6666e8 --- /dev/null +++ b/database/migrations/2023_05_04_130921_create_offline_sync_logs_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('mode', 10); + $table->boolean('error')->nullable()->default(null); + $table->foreignUuid('userId')->nullable(); + $table->foreign('userId')->references('id')->on('users')->nullOnDelete(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('offline_sync_logs'); + } +}; diff --git a/routes/api.php b/routes/api.php index 3424636..2ee7dd8 100644 --- a/routes/api.php +++ b/routes/api.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Route; use App\Http\Controllers\UserController; use App\Http\Controllers\LockerController; +use App\Http\Controllers\OfflineDataController; use App\Http\Controllers\RecordController; use App\Http\Middleware\Localization; use App\Http\Middleware\UnlockMiddleware; @@ -45,6 +46,15 @@ Route::post('unlock', [LockerController::class, 'unlock']); Route::get('record/{lockerNo}', [RecordController::class, 'show']); + + Route::controller(OfflineDataController::class)->group(function () { + Route::get('offline', 'index'); + Route::post('offline', 'requestSync'); + }); + }); + + Route::middleware([UnlockMiddleware::class])->group(function () { + Route::post('RPIunlock', [LockerController::class, 'RPIunlock']); + Route::get('RPIList', [LockerController::class, 'RPIList']); }); - Route::post('RPIunlock', [LockerController::class, 'RPIunlock'])->middleware(UnlockMiddleware::class); });