diff --git a/services/nginx/app/classes/limble.php b/services/nginx/app/classes/limble.php index 687d91f1..cb35adf3 100644 --- a/services/nginx/app/classes/limble.php +++ b/services/nginx/app/classes/limble.php @@ -4,6 +4,7 @@ namespace classes; require_once WD . '/modules/limble/limble_c.php'; require_once WD . '/modules/limble/limble_helpers.php'; +require_once WD . '/modules/limble/classes/limble_endpoints.php'; /** @@ -13,11 +14,12 @@ require_once WD . '/modules/limble/limble_helpers.php'; use Exception; use interfaces\limble_i; +use limble\classes\limble_endpoints; use limble\helpers\limble_tasks; use limble\limble_c; use limble\limble_helpers; -class limble implements limble_i +class limble extends limble_endpoints implements limble_i { /** * The configuration of the module @@ -56,4 +58,15 @@ class limble implements limble_i { return new $this->helpers->tasks(); } + + /** + * Require the webhooks to be enabled + * @throws Exception + */ + public function requireWebhooksEnabled(): void + { + if (!(bool)$this->config->webhooks_enabled->getVariableValue()) { + throw new Exception('Limble webhooks are not enabled'); + } + } } \ No newline at end of file diff --git a/services/nginx/app/index.php b/services/nginx/app/index.php index 4c330f5d..73e749fa 100644 --- a/services/nginx/app/index.php +++ b/services/nginx/app/index.php @@ -67,6 +67,7 @@ require_once 'classes/fxratesapi.php'; require_once 'classes/gatewayapi.php'; require_once 'classes/xlvask.php'; require_once 'classes/entra.php'; +require_once 'classes/limble.php'; /** * Modules diff --git a/services/nginx/app/modules/limble/classes/limble_endpoints.php b/services/nginx/app/modules/limble/classes/limble_endpoints.php new file mode 100644 index 00000000..5630ccc8 --- /dev/null +++ b/services/nginx/app/modules/limble/classes/limble_endpoints.php @@ -0,0 +1,69 @@ +requireModuleEnabled(); + $url = $this->config->api_url . '/tasks'; + $params = [ +// 'status' => 'open', +// 'limit' => 100, + ]; + return $this->sendRequest( + $url, + 'GET', + $params, + [self::getAuthHeader(), 'Content-Type: application/json'] + ); + } + + /** + * @inheritDoc + */ + public function getAuthHeader(): string + { + $this->requireModuleEnabled(); + $client_id = $this->config->client_id->getVariableValue(); + $client_secret = $this->config->client_secret->getVariableValue(); + if (empty($client_id)) { + throw new Exception('Client ID is not set'); + } + if (empty($client_secret)) { + throw new Exception('Client Secret is not set'); + } + // Generate the Basic Auth header + return $this->generateBasicAuthHeader( + (string)$client_id, + (string)$client_secret + ); + } + + /** + * @inheritDoc + * @throws Exception If the module is not enabled + */ + public function getTask(int $taskId): array + { + $this->requireModuleEnabled(); + $url = $this->config->api_url . '/tasks/' . $taskId; + return $this->sendRequest( + $url, + 'GET', + [], + [self::getAuthHeader(), 'Content-Type: application/json'] + ); + } +} \ No newline at end of file diff --git a/services/nginx/app/modules/limble/classes/limble_request.php b/services/nginx/app/modules/limble/classes/limble_request.php new file mode 100644 index 00000000..43596a2a --- /dev/null +++ b/services/nginx/app/modules/limble/classes/limble_request.php @@ -0,0 +1,71 @@ += 300) { + $slack = new \classes\slack(); + echo 'Attempting credentials: ' . $url . ' with method: ' . $method . ' and data: ' . json_encode($data) . "\n"; + echo 'Response: ' . $response . "\n"; + echo 'HTTP Code: ' . $httpCode . "\n"; + echo 'Headers: ' . json_encode($headers) . "\n"; + $slack->send_message('Limble Request Failed: ' . $response, 'Limble Request Error'); + throw new \Exception('Request failed with status code ' . $httpCode); + } + // Check if the response is valid JSON + $responseData = json_decode($response, true); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \Exception('Invalid JSON response: ' . json_last_error_msg()); + } + // Return the response data + return $responseData; + } + + /** + * @inheritDoc + */ + public function generateBasicAuthHeader(string $client_id, string $client_secret): string + { + // Generate the Basic Auth header using the client ID and secret + return 'Authorization: Basic ' . base64_encode($client_id . ':' . $client_secret); + } +} \ No newline at end of file diff --git a/services/nginx/app/modules/limble/helpers/limble_task.php b/services/nginx/app/modules/limble/helpers/limble_task.php new file mode 100644 index 00000000..cf2edbaa --- /dev/null +++ b/services/nginx/app/modules/limble/helpers/limble_task.php @@ -0,0 +1,133 @@ +taskID = $data['taskID'] ?? 0; + $this->name = $data['name'] ?? ''; + $this->userID = $data['userID'] ?? 0; + $this->teamID = $data['teamID'] ?? 0; + $this->locationID = $data['locationID'] ?? 0; + $this->template = $data['template'] ?? false; + $this->createdDate = $data['createdDate'] ?? 0; + $this->startDate = $data['startDate'] ?? 0; + $this->due = $data['due'] ?? 0; + $this->description = $data['description'] ?? ''; + $this->dateCompleted = $data['dateCompleted'] ?? 0; + $this->lastEdited = $data['lastEdited'] ?? 0; + $this->lastEditedByUser = $data['lastEditedByUser'] ?? 0; + $this->completedByUser = $data['completedByUser'] ?? 0; + $this->assetID = $data['assetID'] ?? 0; + $this->completedUserWage = $data['completedUserWage'] ?? 0; + $this->estimatedTime = $data['estimatedTime'] ?? 0; + $this->priority = $data['priority'] ?? 0; + $this->priorityID = $data['priorityID'] ?? 0; + $this->downtime = $data['downtime'] ?? 0; + $this->completionNotes = isset($data['completionNotes']) ? (string)$data['completionNotes'] : ''; + // Optional fields + foreach ( [ + 'requestorName', 'requestorEmail', 'requestorPhone', 'requestTitle', + 'requestField1', 'requestField2', 'requestField3', + 'requestDropdown1', 'requestDropdown2', 'requestDropdown3', + 'requestorDescription', 'meta1', 'meta2', 'meta3', + 'geoLocation' + ] as $field ) { + if (isset($data[$field])) { + $this->$field = (string)$data[$field]; + } else { + $this->$field = null; + } + } + $this->statusID = $data['statusID'] ?? 0; + $this->type = $data['type'] ?? 0; + $this->associatedTaskID = $data['associatedTaskID'] ?? 0; + $this->customTags = $data['customTags'] ?? []; + $this->status = $data['status'] ?? 0; + $this->meta = $data['meta'] ?? []; + $this->requestorName = $data['requestorName'] ?? ''; + $this->requestorEmail = $data['requestorEmail'] ?? ''; + $this->requestorPhone = $data['requestorPhone'] ?? ''; + $this->requestTitle = $data['requestTitle'] ?? ''; + $this->requestField1 = $data['requestField1'] ?? ''; + $this->requestField2 = $data['requestField2'] ?? ''; + $this->requestField3 = $data['requestField3'] ?? ''; + $this->requestDropdown1 = $data['requestDropdown1'] ?? ''; + $this->requestDropdown2 = $data['requestDropdown2'] ?? ''; + $this->requestDropdown3 = $data['requestDropdown3'] ?? ''; + $this->requestorDescription = $data['requestorDescription'] ?? ''; + $this->meta1 = $data['meta1'] ?? ''; + $this->meta2 = $data['meta2'] ?? ''; + $this->meta3 = $data['meta3'] ?? ''; + $this->geoLocation = $data['geoLocation'] ?? ''; + } +} \ No newline at end of file diff --git a/services/nginx/app/modules/limble/helpers/limble_tasks.php b/services/nginx/app/modules/limble/helpers/limble_tasks.php index 5edc85f2..a644089f 100644 --- a/services/nginx/app/modules/limble/helpers/limble_tasks.php +++ b/services/nginx/app/modules/limble/helpers/limble_tasks.php @@ -4,5 +4,29 @@ namespace limble\helpers; class limble_tasks { + /** + * Format an array of tasks into an array of limble_task objects + * @param array $tasks + * @return limble_task[] + * @see limble_task + */ + public function formatTasks(array $tasks): array + { + $formattedTasks = []; + foreach ( $tasks as $task ) { + $formattedTasks[] = $this->formatTask($task); + } + return $formattedTasks; + } + /** + * Format a task array into a limble_task object + * @param array $task + * @return limble_task + * @see limble_task + */ + public function formatTask(array $task): limble_task + { + return new limble_task($task); + } } \ No newline at end of file diff --git a/services/nginx/app/modules/limble/helpers/limble_webhook_payload.php b/services/nginx/app/modules/limble/helpers/limble_webhook_payload.php new file mode 100644 index 00000000..c3ab6aff --- /dev/null +++ b/services/nginx/app/modules/limble/helpers/limble_webhook_payload.php @@ -0,0 +1,23 @@ +payload = $payload; + } + +} \ No newline at end of file diff --git a/services/nginx/app/modules/limble/helpers/limble_webhook_payload_task.php b/services/nginx/app/modules/limble/helpers/limble_webhook_payload_task.php new file mode 100644 index 00000000..ee2e24ac --- /dev/null +++ b/services/nginx/app/modules/limble/helpers/limble_webhook_payload_task.php @@ -0,0 +1,62 @@ +taskID = (int)($payload['taskID'] ?? 0); + $this->status = (string)($payload['status'] ?? ''); + $this->category = (string)($payload['category'] ?? ''); + $this->user = (string)($payload['user'] ?? ''); + $this->taskObject = new limble_task(((new limble())->getTask($payload['taskID'])) ?: []); + } +} \ No newline at end of file diff --git a/services/nginx/app/modules/limble/interfaces/limble_endpoints_i.php b/services/nginx/app/modules/limble/interfaces/limble_endpoints_i.php new file mode 100644 index 00000000..49cb8873 --- /dev/null +++ b/services/nginx/app/modules/limble/interfaces/limble_endpoints_i.php @@ -0,0 +1,28 @@ + 'Update entra config' ] ); + /** Limble config > GET */ + $this->get('/limble/config', function () { + global $response; + $this->requirePermission('modules_limble_config'); + $user = (new authentication())->get_user(); + if ($user) { + (new logs_o())->add('limble_config', 'global', 1, $user->id, 'LIMBLE_CONFIG', 'Successfully fetched limble config'); + $response->success( + (new \classes\limble())->config->getConfigRequest() + ); + } else { + (new logs_o())->add('limble_config', 'global', 1, 0, 'LIMBLE_CONFIG', 'No user found, or invalid session'); + $response->error('Invalid session', 400); + } + }, + [ + 'modules_limble_config' => 'Get limble config' + ] + ); + /** Limble config > POST */ + $this->post('/limble/config', function () { + global $response; + $this->requirePermission('modules_limble_config'); + $user = (new authentication())->get_user(); + if ($user) { + (new logs_o())->add('limble_config', 'global', 1, $user->id, 'LIMBLE_CONFIG', 'Successfully updated limble config'); + $response->success( + (new \classes\limble())->config->postConfigRequest() + ); + } else { + (new logs_o())->add('limble_config', 'global', 1, 0, 'LIMBLE_CONFIG', 'No user found, or invalid session'); + $response->error('Invalid session', 400); + } + }, + [ + 'modules_limble_config' => 'Update limble config' + ] + ); } } \ No newline at end of file diff --git a/services/nginx/app/routes/moduleLimbleRoute.php b/services/nginx/app/routes/moduleLimbleRoute.php new file mode 100644 index 00000000..3a187bf6 --- /dev/null +++ b/services/nginx/app/routes/moduleLimbleRoute.php @@ -0,0 +1,58 @@ +post('/modules/limble/webhook/task', function () { + global $response; + $slack = new slack(); + $slack->send_message('Limble Webhook Task Triggered', 'Limble Webhook'); + //TODO: Add authentication of some sort here + //self::requirePermission('modules_limble_webhooks_task'); + // Check if the module is enabled + $limble = new limble(); + $limble->requireModuleEnabled(); + $limble->requireWebhooksEnabled(); + $payload = file_get_contents('php://input'); + $slack->send_message(json_encode($payload), 'Limble Webhook'); + // Response + $response->success('Debug', 200); + }, + [ + 'modules_limble_webhooks_task' => 'Send Limble Webhook Task (POST)', + ] + ); + + $this->get('/modules/limble/tasks', function () { + global $response; + $slack = new slack(); + $slack->send_message('Limble Tasks Endpoint Triggered', 'Limble Tasks'); + //self::requirePermission('modules_limble_tasks'); + // Check if the module is enabled + $limble = new limble(); + $limble->requireModuleEnabled(); + // Get the tasks + $tasks = $limble->getTasks()->formatTasks($limble->listTasks()); + // Response + $response->success($tasks, 200); + }, + [ + 'modules_limble_tasks' => 'Get Limble Tasks (GET)', + ] + ); + } +} \ No newline at end of file