From dae0cd481d96876d0f980e0f07a246fa88e18405 Mon Sep 17 00:00:00 2001 From: arifal Date: Fri, 31 Jan 2025 18:01:27 +0700 Subject: [PATCH] fix handle token login when loop and fix width column on task fix color default danger success scss, fix add timeout on php.ini, add scraping for execute from api, add check api for handle disabled button sync --- .../Api/ImportDatasourceController.php | 17 ++++ .../Controllers/Api/ScrapingController.php | 61 ++++++++++++++ app/Models/ImportDatasource.php | 2 + app/ServiceClient.php | 4 +- app/ServiceSIMBG.php | 80 +++++++++--------- app/Traits/GlobalApiResponse.php | 4 - resources/js/master/users/users.js | 4 +- .../request-assignment/request-assignment.js | 12 +-- .../js/settings/general/general-settings.js | 4 +- .../js/settings/syncronize/syncronize.js | 81 +++++++++++++++---- resources/scss/config/_variables.scss | 8 +- .../views/layouts/partials/topbar.blade.php | 16 ++-- .../views/settings/general/create.blade.php | 5 +- .../views/settings/syncronize/index.blade.php | 7 +- routes/api.php | 18 +++-- 15 files changed, 233 insertions(+), 90 deletions(-) create mode 100644 app/Http/Controllers/Api/ScrapingController.php diff --git a/app/Http/Controllers/Api/ImportDatasourceController.php b/app/Http/Controllers/Api/ImportDatasourceController.php index dd634a6..f77c4a0 100644 --- a/app/Http/Controllers/Api/ImportDatasourceController.php +++ b/app/Http/Controllers/Api/ImportDatasourceController.php @@ -2,13 +2,17 @@ namespace App\Http\Controllers\Api; +use App\Enums\ImportDatasourceStatus; use App\Http\Controllers\Controller; use App\Http\Resources\ImportDatasourceResource; use App\Models\ImportDatasource; +use App\Traits\GlobalApiResponse; +use Exception; use Illuminate\Http\Request; class ImportDatasourceController extends Controller { + use GlobalApiResponse; /** * Display a listing of the resource. */ @@ -23,6 +27,19 @@ class ImportDatasourceController extends Controller return ImportDatasourceResource::collection($query->paginate()); } + public function checkImportDatasource(){ + try{ + $data = ImportDatasource::where("status",ImportDatasourceStatus::Processing->value )->count(); + $result = [ + "can_execute" => $data === 0, + "total_processing" => $data + ]; + return response()->json( $result , 200); + }catch(Exception $ex){ + return response()->json(["message" => $ex->getMessage(), 500]); + } + } + /** * Store a newly created resource in storage. */ diff --git a/app/Http/Controllers/Api/ScrapingController.php b/app/Http/Controllers/Api/ScrapingController.php new file mode 100644 index 0000000..ef8b7ff --- /dev/null +++ b/app/Http/Controllers/Api/ScrapingController.php @@ -0,0 +1,61 @@ +value)->count(); + if($check_datasource > 0){ + return $this->resError("Failed to execute while processing another scraping"); + } + + // run service artisan command + Artisan::call("app:execute-scraping"); + return $this->resSuccess("Success execute scraping service please wait"); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + // + } + + /** + * Display the specified resource. + */ + public function show(string $id) + { + // + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, string $id) + { + // + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(string $id) + { + // + } +} diff --git a/app/Models/ImportDatasource.php b/app/Models/ImportDatasource.php index 887c14b..9bdb995 100644 --- a/app/Models/ImportDatasource.php +++ b/app/Models/ImportDatasource.php @@ -2,10 +2,12 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class ImportDatasource extends Model { + use HasFactory; protected $table = 'import_datasources'; protected $fillable = [ 'id', diff --git a/app/ServiceClient.php b/app/ServiceClient.php index 3595bce..21edd49 100644 --- a/app/ServiceClient.php +++ b/app/ServiceClient.php @@ -26,13 +26,15 @@ class ServiceClient ); } - public function makeRequest($url, $method = 'GET', $body = null, $headers = []){ + public function makeRequest($url, $method = 'GET', $body = null, $headers = [], $timeout = 300){ try { $headers = array_merge($this->headers, $headers); $options = [ 'headers' => $headers, + 'timeout' => $timeout, + 'connect_timeout' => 60 ]; if ($body) { diff --git a/app/ServiceSIMBG.php b/app/ServiceSIMBG.php index c65a52d..b4f17d2 100644 --- a/app/ServiceSIMBG.php +++ b/app/ServiceSIMBG.php @@ -48,21 +48,13 @@ class ServiceSIMBG return $res; } - public function syncIndexIntegration($uuid) + public function syncIndexIntegration($uuid, $token) { $clientHelper = new ServiceClient($this->simbg_host); $url = "/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/"; - $resToken = $this->getToken(); - - if (!isset($resToken) || empty($resToken->original['data']['token']['access'])) { - // Log error - Log::error("Token not retrieved for syncIndexIntegration", ['uuid' => $uuid]); - return null; - } - - $apiToken = $resToken->original['data']['token']['access']; + $headers = [ - 'Authorization' => "Bearer " . $apiToken, + 'Authorization' => "Bearer " . $token, ]; $res = $clientHelper->get($url, $headers); @@ -70,16 +62,16 @@ class ServiceSIMBG if (empty($res->original['success']) || !$res->original['success']) { // Log error Log::error("API response indicates failure", ['url' => $url, 'uuid' => $uuid]); - return null; + return false; } $data = $res->original['data']['data'] ?? null; if (!$data) { Log::error("No valid data returned from API", ['url' => $url, 'uuid' => $uuid]); - return null; + return false; } - PbgTaskIndexIntegrations::updateOrCreate( + $resultData = PbgTaskIndexIntegrations::updateOrCreate( ['pbg_task_uid' => $uuid], [ 'indeks_fungsi_bangunan' => $data['indeks_fungsi_bangunan'] ?? null, @@ -93,19 +85,25 @@ class ServiceSIMBG ); // Log success - Log::info("syncIndexIntegration completed successfully", ['uuid' => $uuid]); + if ($resultData->wasRecentlyCreated) { + Log::info("integration created successfully", ['uuid' => $uuid]); + } else { + Log::info("integration updated successfully", ['uuid' => $uuid]); + } + + return true; } public function syncTaskList() { $clientHelper = new ServiceClient($this->simbg_host); - $resToken = $this->getToken(); + $initResToken = $this->getToken(); $importDatasource = ImportDatasource::create([ 'status' => ImportDatasourceStatus::Processing->value, ]); - if (empty($resToken->original['data']['token']['access'])) { + if (empty($initResToken->original['data']['token']['access'])) { $importDatasource->update([ 'status' => ImportDatasourceStatus::Failed->value, 'message' => 'Failed to retrieve token' @@ -113,14 +111,14 @@ class ServiceSIMBG return $this->resError("Failed to retrieve token"); } - $apiToken = $resToken->original['data']['token']['access']; + $apiToken = $initResToken->original['data']['token']['access']; $headers = ['Authorization' => "Bearer " . $apiToken]; $url = "/api/pbg/v1/list/?page=1&size={$this->fetch_per_page}&sort=ASC"; $initialResponse = $clientHelper->get($url, $headers); $totalPage = $initialResponse->original['data']['total_page'] ?? 0; - if ($totalPage === 0) { + if ($totalPage == 0) { $importDatasource->update([ 'status' => ImportDatasourceStatus::Failed->value, 'message' => 'Invalid response: no total_page' @@ -132,14 +130,26 @@ class ServiceSIMBG for ($currentPage = 1; $currentPage <= $totalPage; $currentPage++) { $pageUrl = "/api/pbg/v1/list/?page={$currentPage}&size={$this->fetch_per_page}&sort=ASC"; - $token = $this->getToken(); + $getToken = $this->getToken(); + if (empty($getToken->original['data']['token']['access'])) { + $importDatasource->update([ + 'status' => ImportDatasourceStatus::Failed->value, + 'message' => 'Failed to retrieve token' + ]); + break; + } + $token = $getToken->original['data']['token']['access']; $headers = ['Authorization' => "Bearer " . $token]; $response = $clientHelper->get($pageUrl, $headers); $tasks = $response->original['data']['data'] ?? []; if (empty($tasks)) { + $importDatasource->update([ + 'status' => ImportDatasourceStatus::Failed->value, + 'message' => 'No data found on page' + ]); Log::warning("No data found on page", ['page' => $currentPage]); - continue; + break; } Log::info("executed page", ['page' => $currentPage, 'total' => $totalPage]); @@ -170,15 +180,20 @@ class ServiceSIMBG 'created_at' => now(), ]; - $this->syncIndexIntegration($item['uid']); - $this->syncTaskDetailSubmit($item['uid']); + $this->syncIndexIntegration($item['uid'], $token); + $this->syncTaskDetailSubmit($item['uid'], $token); $savedCount++; } catch (Exception $e) { $failedCount++; + $importDatasource->update([ + 'status' => ImportDatasourceStatus::Failed->value, + 'message' => "Successfully processed: $savedCount, Failed: $failedCount" + ]); Log::error("Failed to process task", [ 'error' => $e->getMessage(), 'task' => $item, ]); + break; } } @@ -201,21 +216,13 @@ class ServiceSIMBG } - public function syncTaskDetailSubmit($uuid) + public function syncTaskDetailSubmit($uuid, $token) { $clientHelper = new ServiceClient($this->simbg_host); - $resToken = $this->getToken(); - if (!isset($resToken) || empty($resToken->original['data']['token']['access'])) { - // Log error - Log::error("Token not retrieved for syncTaskDetailSubmit"); - return null; - } - - $apiToken = $resToken->original['data']['token']['access']; $url = "/api/pbg/v1/detail/" . $uuid . "/retribution/submit/"; $headers = [ - 'Authorization' => "Bearer " . $apiToken, + 'Authorization' => "Bearer " . $token, ]; $res = $clientHelper->get($url, $headers); @@ -223,13 +230,13 @@ class ServiceSIMBG if (empty($res->original['success']) || !$res->original['success']) { // Log error Log::error("API response indicates failure", ['url' => $url, 'uuid' => $uuid]); - return null; + return false; } $data = $res->original['data']['data'] ?? []; if (empty($data)) { Log::error("No data returned from API", ['url' => $url, 'uuid' => $uuid]); - return null; + return false; } $detailCreatedAt = isset($data['created_at']) @@ -281,7 +288,8 @@ class ServiceSIMBG PbgTaskPrasarana::upsert($insertData, ['pbg_task_uid', 'prasarana_id']); } - Log::info("syncTaskDetailSubmit completed successfully", ['uuid' => $uuid]); + Log::info("retribution and prasarana successfully", ['uuid' => $uuid]); + return true; } } diff --git a/app/Traits/GlobalApiResponse.php b/app/Traits/GlobalApiResponse.php index 8d84aca..faff6ad 100644 --- a/app/Traits/GlobalApiResponse.php +++ b/app/Traits/GlobalApiResponse.php @@ -12,10 +12,6 @@ trait GlobalApiResponse 'success' => true, 'data' => $result ]; - - if(!empty($message)){ - $response['message'] = $message; - } return response()->json($response, $code); } diff --git a/resources/js/master/users/users.js b/resources/js/master/users/users.js index bd42f27..90a3b13 100644 --- a/resources/js/master/users/users.js +++ b/resources/js/master/users/users.js @@ -37,7 +37,9 @@ class UsersTable { url: `${GlobalConfig.apiHost}/api/users`, credentials: "include", headers: { - Authorization: `Bearer ${localStorage.getItem("token")}`, + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, "Content-Type": "application/json", }, then: (data) => diff --git a/resources/js/request-assignment/request-assignment.js b/resources/js/request-assignment/request-assignment.js index 3c7ec21..f270293 100644 --- a/resources/js/request-assignment/request-assignment.js +++ b/resources/js/request-assignment/request-assignment.js @@ -11,15 +11,15 @@ class RequestAssignment { new Grid({ columns: [ "ID", - "Name", - "Condition", + {name: "Name", width: "15%"}, + {name: "Condition", width: "7%"}, "Registration Number", "Document Number", - "Address", + {name: "Address", width: "30%"}, "Status", "Function Type", "Consultation Type", - "Due Date", + {name: "Due Date", width: "7%"}, ], search: { server: { @@ -40,7 +40,9 @@ class RequestAssignment { url: `${GlobalConfig.apiHost}/api/request-assignments`, credentials: "include", headers: { - Authorization: `Bearer ${localStorage.getItem("token")}`, + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, "Content-Type": "application/json", }, then: (data) => diff --git a/resources/js/settings/general/general-settings.js b/resources/js/settings/general/general-settings.js index ef29a76..383ab6b 100644 --- a/resources/js/settings/general/general-settings.js +++ b/resources/js/settings/general/general-settings.js @@ -22,8 +22,8 @@ class SyncronizeTask { console.log("cell data", cell); return gridjs.html(`
- Update - + Update +
`); }, diff --git a/resources/js/settings/syncronize/syncronize.js b/resources/js/settings/syncronize/syncronize.js index eb10c58..a09b5d1 100644 --- a/resources/js/settings/syncronize/syncronize.js +++ b/resources/js/settings/syncronize/syncronize.js @@ -6,7 +6,7 @@ import GlobalConfig from "../../global-config.js"; class SyncronizeTask { init() { this.initTableImportDatasources(); - this.onSyncSubmit(); + this.handleSubmitSync(); } initTableImportDatasources() { new Grid({ @@ -46,20 +46,71 @@ class SyncronizeTask { }, }).render(document.getElementById("table-import-datasources")); } - onSyncSubmit() { - const form = document.getElementById("sync-form"); - if (form) { - form.addEventListener("submit", function (event) { - event.preventDefault(); // Prevent the default form submission - - const button = document.getElementById("btn-sync-submit"); - if (button) { - button.disabled = true; - button.innerText = "Processing..."; - } - form.submit(); - }); - } + handleSubmitSync() { + const button = document.getElementById("btn-sync-submit"); + + // Check if the button should be enabled or disabled based on the status + fetch(`${GlobalConfig.apiHost}/api/import-datasource/check-datasource`, { + method: "GET", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + } + }) + .then(response => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then(data => { + console.log("data check button sync", data.can_execute); + button.disabled = !data.can_execute; + + // If the button is enabled, add click event to trigger sync + if (!button.disabled) { + button.addEventListener("click", function(e) { + button.disabled = true; // Disable button to prevent multiple clicks + button.textContent = "Syncing..."; // Change button text to show syncing + + // Trigger the scraping API call + fetch(`${GlobalConfig.apiHost}/api/scraping`, { + method: "GET", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + } + }) + .then(response => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then(data => { + console.log("data sync button", data); + alert("Synchronization executed successfully"); + window.location.reload(); + }) + .catch(err => { + console.error("Fetch error:", err); + alert("An error occurred during synchronization"); + }) + .finally(() => { + button.disabled = false; // Re-enable the button after the request is complete + button.textContent = "Sync Data"; // Reset button text + }); + }); + } + }) + .catch(err => { + console.error("Fetch error:", err); + alert("An error occurred while checking the datasource"); + }); } } document.addEventListener("DOMContentLoaded", function (e) { diff --git a/resources/scss/config/_variables.scss b/resources/scss/config/_variables.scss index 8b92a24..8a129fc 100755 --- a/resources/scss/config/_variables.scss +++ b/resources/scss/config/_variables.scss @@ -64,10 +64,10 @@ $blue: #1a80f8; $indigo: #53389f; $purple: #7e67fe; $pink: #ff86c8; -$red: #ed321f; +$red: #bd1300; $orange: #f0934e; -$yellow: #fb9f68; -$green: #21d760; +$yellow: #dfdc40; +$green: #00c91b; $teal: #040505; $cyan: #1ab0f8; // scss-docs-end color-variables @@ -81,7 +81,7 @@ $purple: $purple; $pink: $pink; $danger: $red; $orange: $orange; -$warning: $orange; +$warning: $yellow; $success: $green; $info: $cyan; $light: $gray-200; diff --git a/resources/views/layouts/partials/topbar.blade.php b/resources/views/layouts/partials/topbar.blade.php index 9b6cae6..39795b6 100755 --- a/resources/views/layouts/partials/topbar.blade.php +++ b/resources/views/layouts/partials/topbar.blade.php @@ -11,25 +11,25 @@ -