From 035d26c62daf9b904f388265d48bd4263de27fc7 Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Wed, 27 Dec 2023 19:54:01 -0500 Subject: [PATCH 1/2] Drop integration with dead webservices plugin --- hook.php | 15 --- inc/model.class.php | 25 +---- inc/webservice.class.php | 208 --------------------------------------- setup.php | 2 - testwebservice.php | 125 ----------------------- 5 files changed, 3 insertions(+), 372 deletions(-) delete mode 100644 inc/webservice.class.php delete mode 100644 testwebservice.php diff --git a/hook.php b/hook.php index 969fe791..5110626c 100644 --- a/hook.php +++ b/hook.php @@ -28,21 +28,6 @@ * ------------------------------------------------------------------------- */ -function plugin_datainjection_registerMethods() { - - global $WEBSERVICES_METHOD; - - $methods = ['getModel' => 'methodGetModel', - 'listModels' => 'methodListModels', - 'inject' => 'methodInject', - 'listItemtypes' => 'methodListItemtypes']; - - foreach ($methods as $code => $method) { - $WEBSERVICES_METHOD['datainjection.'.$code] = ['PluginDatainjectionWebservice', $method]; - } -} - - function plugin_datainjection_install() { global $DB; diff --git a/inc/model.class.php b/inc/model.class.php index 041ff133..15238352 100644 --- a/inc/model.class.php +++ b/inc/model.class.php @@ -1029,19 +1029,7 @@ function processUploadedFile($options = []) { $this->loadSpecificModel(); $response = $this->readUploadedFile($options); if (!$this->injectionData) { - if (!isset($options['webservice'])) { - return false; - } - return PluginWebservicesMethodCommon::Error( - $options['protocol'], - WEBSERVICES_ERROR_FAILED, - sprintf( - __( - 'Not data to import', - 'datainjection' - ) - ) - ); + return false; } if ($mode == self::PROCESS) { @@ -1055,15 +1043,8 @@ function processUploadedFile($options = []) { if ($check['status']!= PluginDatainjectionCommonInjectionLib::SUCCESS) { if ($mode == self::PROCESS) { - if (!isset($options['webservice'])) { - Session::addMessageAfterRedirect($check['error_message'], true, ERROR); - return false; - } - return PluginWebservicesMethodCommon::Error( - $options['protocol'], - WEBSERVICES_ERROR_FAILED, - $check['error_message'] - ); + Session::addMessageAfterRedirect($check['error_message'], true, ERROR); + return false; } } diff --git a/inc/webservice.class.php b/inc/webservice.class.php deleted file mode 100644 index b1e5de1d..00000000 --- a/inc/webservice.class.php +++ /dev/null @@ -1,208 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. - * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html - * @link https://github.com/pluginsGLPI/datainjection - * ------------------------------------------------------------------------- - */ - -class PluginDatainjectionWebservice -{ - - - static function methodInject($params, $protocol) { - - if (isset($params['help'])) { - return ['uri' => 'string,mandatory', - 'base64' => 'string,optional', - 'additional' => 'array,optional', - 'models_id' => 'integer, mandatory', - 'entities_id'=> 'integer,mandatory', - 'mandatory' => 'array,optional', - 'uri' => 'uri,mandatory', - 'help' => 'bool,optional']; - } - - $model = new PluginDatainjectionModel(); - - //----------------------------------------------------------------- - //-------------------------- Check parameters --------------------- - //----------------------------------------------------------------- - if (!isset($_SESSION['glpiID'])) { - return PluginWebservicesMethodCommon::Error( - $protocol, - WEBSERVICES_ERROR_NOTAUTHENTICATED - ); - } - - if (!isset($params['uri']) && !isset($params['base64'])) { - return PluginWebservicesMethodCommon::Error( - $protocol, - WEBSERVICES_ERROR_MISSINGPARAMETER, - '', 'uri or base64' - ); - } - - if (!isset($params['models_id'])) { - return PluginWebservicesMethodCommon::Error( - $protocol, - WEBSERVICES_ERROR_MISSINGPARAMETER, - 'models_id' - ); - } - if (!$model->getFromDB($params['models_id'])) { - return PluginWebservicesMethodCommon::Error( - $protocol, WEBSERVICES_ERROR_NOTFOUND, - __('Model unknown', 'datainjection') - ); - - } - if (!$model->can($params['models_id'], READ)) { - return PluginWebservicesMethodCommon::Error( - $protocol, WEBSERVICES_ERROR_NOTALLOWED, - __( - 'You cannot access this model', - 'datainjection' - ) - ); - } - if ($model->fields['step'] < PluginDatainjectionModel::READY_TO_USE_STEP) { - return PluginWebservicesMethodCommon::Error( - $protocol, WEBSERVICES_ERROR_NOTALLOWED, - __( - 'You cannot access this model', - 'datainjection' - ) - ); - } - - //Check entity - if (!isset($params['entities_id'])) { - return PluginWebservicesMethodCommon::Error( - $protocol, - WEBSERVICES_ERROR_MISSINGPARAMETER, - 'entities_id' - ); - } - $entities_id = $params['entities_id']; - if ($entities_id > 0) { - $entity = new Entity(); - if (!$entity->getFromDB($entities_id)) { - return PluginWebservicesMethodCommon::Error( - $protocol, WEBSERVICES_ERROR_NOTFOUND, - __('Entity unknown', 'datainjection') - ); - - } - if (!Session::haveAccessToEntity($entities_id)) { - return PluginWebservicesMethodCommon::Error( - $protocol, WEBSERVICES_ERROR_NOTALLOWED, - __( - 'You cannot access this entity', - 'datainjection' - ) - ); - } - } - - //Mandatory fields - $additional_infos = []; - if (isset($params['additional']) && is_array($params['additional'])) { - $additional_infos = $params['additional']; - } - - //Upload CSV file - $document_name = basename($params['uri']); - $filename = tempnam(PLUGIN_DATAINJECTION_UPLOAD_DIR, 'PWS'); - $response = PluginWebservicesMethodCommon::uploadDocument( - $params, $protocol, $filename, - $document_name - ); - - if (PluginWebservicesMethodCommon::isError($protocol, $response)) { - return $response; - } - - //Uploade successful : now perform import ! - $options = ['file_encoding' => PluginDatainjectionBackend::ENCODING_AUTO, //Detect automatically file encoding - 'webservice' => true, //Use webservice CSV file import - 'original_filename' => $params['uri'], //URI to the CSV file - 'unique_filename' => $filename, //Unique filename - 'mode' => PluginDatainjectionModel::PROCESS, - 'delete_file' => false, //Do not delete file once imported - 'protocol' => $protocol]; //The Webservice protocol used - - $results = []; - $response = $model->processUploadedFile($options); - if (!PluginWebservicesMethodCommon::isError($protocol, $response)) { - $engine = new PluginDatainjectionEngine( - $model, - $additional_infos, - $params['entities_id'] - ); - //Remove first line if header is present - $first = true; - foreach ($model->injectionData->getData() as $id => $data) { - if ($first && $model->getSpecificModel()->isHeaderPresent()) { - $first = false; - } else { - $results[] = $engine->injectLine($data[0], $id); - } - } - $model->cleanData(); - return $results; - } - return $response; - } - - - static function methodGetModel($params, $protocol) { - - $params['itemtype'] = 'PluginDatainjectionModel'; - return PluginWebservicesMethodInventaire::methodGetObject($params, $protocol); - } - - - static function methodListModels($params, $protocol) { - - $params['itemtype'] = 'PluginDatainjectionModel'; - return PluginWebservicesMethodInventaire::methodListObjects($params, $protocol); - } - - - static function methodListItemtypes($params, $protocol) { - - if (isset($params['help'])) { - return ['help' => 'bool,optional']; - } - - if (!isset($_SESSION['glpiID'])) { - return self::Error($protocol, WEBSERVICES_ERROR_NOTAUTHENTICATED); - } - - return PluginDatainjectionInjectionType::getItemtypes(); - } - -} diff --git a/setup.php b/setup.php index 6f0f6ed6..ba1c35a3 100644 --- a/setup.php +++ b/setup.php @@ -80,8 +80,6 @@ function plugin_init_datainjection() { // Javascript file $PLUGIN_HOOKS['add_javascript']['datainjection'] = 'js/datainjection.js'; - // Inbtegration with Webservices plugin - $PLUGIN_HOOKS['webservices']['datainjection'] = 'plugin_datainjection_registerMethods'; $INJECTABLE_TYPES = []; } diff --git a/testwebservice.php b/testwebservice.php deleted file mode 100644 index d03bb2c2..00000000 --- a/testwebservice.php +++ /dev/null @@ -1,125 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. - * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html - * @link https://github.com/pluginsGLPI/datainjection - * ------------------------------------------------------------------------- - */ - -if (!extension_loaded("xmlrpc")) { - die("Extension xmlrpc not loaded\n"); -} - -chdir(dirname($_SERVER["SCRIPT_FILENAME"])); -chdir("../../.."); -$url = "/".basename(getcwd()).Plugin::getWebDir('webservices', false)."/xmlrpc.php"; - -$args = []; -if ($_SERVER['argc'] > 1) { - for ($i=1; $i [ - 'method' => "POST", - 'header' => $header, - 'content' => $request - ] - ] - ); - - $file = file_get_contents("http://".$params['host']."/".$params['url'], false, $context); - if (!$file) { - die("+ No response\n"); - } - - $response = xmlrpc_decode($file); - if (!is_array($response)) { - echo $file; - die ("+ Bad response\n"); - } - - if (xmlrpc_is_fault($response)) { - echo("xmlrpc error(".$response['faultCode']."): ".$response['faultString']."\n"); - return false; - } - return $response; -} From 67dda3586b2da2fcdf8945f7f13de6df2ffb8df0 Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Wed, 27 Dec 2023 23:12:33 -0500 Subject: [PATCH 2/2] hl api integration --- inc/apicontroller.class.php | 227 ++++++++++++++++++++++++++++++++++++ inc/backend.class.php | 1 + inc/engine.class.php | 4 +- inc/model.class.php | 10 +- setup.php | 4 +- 5 files changed, 238 insertions(+), 8 deletions(-) create mode 100644 inc/apicontroller.class.php diff --git a/inc/apicontroller.class.php b/inc/apicontroller.class.php new file mode 100644 index 00000000..53a7a8a6 --- /dev/null +++ b/inc/apicontroller.class.php @@ -0,0 +1,227 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/datainjection + * ------------------------------------------------------------------------- + */ + +use Glpi\Api\HL\Controller\AbstractController; +use Glpi\Api\HL\Doc as Doc; +use Glpi\Api\HL\Route; +use Glpi\Api\HL\Search; +use Glpi\Http\JSONResponse; +use Glpi\Http\Request; +use Glpi\Http\Response; +use GuzzleHttp\Psr7\Utils; + +#[Route(path: '/Plugin/DataInjection', requirements: [ + 'id' => '\d+' +], priority: 1, tags: ['Data Injection'])] +class PluginDatainjectionApiController extends AbstractController +{ + protected static function getRawKnownSchemas(): array + { + return [ + 'DataInjectionModel' => [ + 'type' => Doc\Schema::TYPE_OBJECT, + 'x-itemtype' => PluginDatainjectionModel::class, + 'properties' => [ + 'id' => [ + 'type' => Doc\Schema::TYPE_INTEGER, + 'format' => Doc\Schema::FORMAT_INTEGER_INT64, + ], + 'name' => ['type' => Doc\Schema::TYPE_STRING], + 'comment' => ['type' => Doc\Schema::TYPE_STRING], + 'itemtype' => ['type' => Doc\Schema::TYPE_STRING], + 'entity' => self::getDropdownTypeSchema(class: Entity::class, full_schema: 'Entity'), + 'date_creation' => ['type' => Doc\Schema::TYPE_STRING, 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME], + 'date_mod' => ['type' => Doc\Schema::TYPE_STRING, 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME], + 'allow_add' => [ + 'type' => Doc\Schema::TYPE_BOOLEAN, + 'x-field' => 'behavior_add', + 'description' => 'Allow creation of new items' + ], + 'allow_update' => [ + 'type' => Doc\Schema::TYPE_BOOLEAN, + 'x-field' => 'behavior_update', + 'description' => 'Allow update of existing items' + ], + 'allow_add_linked_items' => [ + 'type' => Doc\Schema::TYPE_BOOLEAN, + 'x-field' => 'can_add_dropdown', + 'description' => 'Allow creation of dropdowns/linked items' + ], + 'allow_overwrite_fields' => [ + 'type' => Doc\Schema::TYPE_BOOLEAN, + 'x-field' => 'can_overwrite_if_not_empty', + 'description' => 'Allow update of existing fields' + ], + 'is_private' => ['type' => Doc\Schema::TYPE_BOOLEAN], + 'user' => self::getDropdownTypeSchema(class: User::class, full_schema: 'User'), + 'date_format' => ['type' => Doc\Schema::TYPE_STRING], + 'float_format' => ['type' => Doc\Schema::TYPE_STRING], + 'unique_ports' => [ + 'type' => Doc\Schema::TYPE_BOOLEAN, + 'x-field' => 'port_unicity', + ], + 'csv_options' => [ + 'type' => Doc\Schema::TYPE_OBJECT, + 'x-join' => [ + 'table' => 'glpi_plugin_datainjection_modelcsvs', + 'field' => 'models_id', + 'fkey' => 'id', + 'primary-property' => 'id', + ], + 'properties' => [ + 'id' => [ + 'type' => Doc\Schema::TYPE_INTEGER, + 'format' => Doc\Schema::FORMAT_INTEGER_INT64, + ], + 'model' => self::getDropdownTypeSchema(class: PluginDatainjectionModel::class, field: 'models_id'), + 'delimiter' => [ + 'type' => Doc\Schema::TYPE_STRING, + ], + 'is_header_present' => [ + 'type' => Doc\Schema::TYPE_BOOLEAN, + ], + ] + ] + ] + ] + ]; + } + + #[Route(path: '/Model', methods: ['GET'])] + #[Doc\Route( + description: 'List or search data injection models', + responses: [ + ['schema' => 'DataInjectionModel[]'] + ] + )] + public function getModels(Request $request): Response + { + $response = Search::searchBySchema($this->getKnownSchema('DataInjectionModel'), $request->getParameters()); + $decoded = json_decode((string) $response->getBody(), true); + foreach ($decoded as &$model) { + // Keep only the id and name of the model + $model['csv_options']['model'] = [ + 'id' => $model['csv_options']['model']['id'], + 'name' => $model['csv_options']['model']['name'], + ]; + } + unset($model); + $response = $response->withBody(Utils::streamFor(json_encode($decoded))); + return $response; + } + + #[Route(path: '/Model/{id}', methods: ['GET'])] + #[Doc\Route( + description: 'Get a data injection model', + responses: [ + ['schema' => 'DataInjectionModel'] + ] + )] + public function getModel(Request $request): Response + { + return Search::getOneBySchema($this->getKnownSchema('DataInjectionModel'), $request->getAttributes(), $request->getParameters()); + } + + #[Route(path: '/Model/{id}/Injection', methods: ['POST'])] + #[Doc\Route( + description: 'Inject data using the specified model', + parameters: [ + [ + 'name' => '_', + 'location' => Doc\Parameter::LOCATION_BODY, + 'schema' => [ + 'type' => Doc\Schema::TYPE_OBJECT, + 'properties' => [ + 'filename' => [ + 'type' => Doc\Schema::TYPE_STRING, + 'format' => Doc\Schema::FORMAT_STRING_BINARY + ] + ] + ], + 'required' => false, + 'content_type' => 'multipart/form-data' + ], + ] + )] + public function inject(Request $request): Response + { + $model = new PluginDatainjectionModel(); + if (!$model->getFromDB($request->getAttribute('id'))) { + return self::getNotFoundErrorResponse(); + } + + $results = []; + foreach ($request->getUploadedFiles() as $file) { + $options = [ + 'file_encoding' => PluginDatainjectionBackend::ENCODING_AUTO, + 'from_api' => true, + 'original_filename' => $file['name'], + 'unique_filename' => $file['tmp_name'], + 'mode' => PluginDatainjectionModel::PROCESS, + 'delete_file' => true, + ]; + $action_results = []; + $success = $model->processUploadedFile($options); + if (!$success) { + return new JSONResponse( + self::getErrorResponseBody(AbstractController::ERROR_GENERIC, 'Error processing file'), + 400 + ); + } + $engine = new PluginDatainjectionEngine($model, [], $_SESSION['glpiactive_entity'] ?? 0); + $first = true; + foreach ($model->injectionData->getData() as $id => $data) { + if ($first && $model->getSpecificModel()->isHeaderPresent()) { + $first = false; + } else { + $action_results[] = $engine->injectLine($data[0], $id); + } + } + $model->cleanData(); + $results[] = [ + 'filename' => $file['name'], + 'results' => $action_results + ]; + } + return new JSONResponse($results); + } + + #[Route(path: '/Itemtype', methods: ['GET'])] + #[Doc\Route( + description: 'List item types', + responses: [ + ['schema' => 'string[]'] + ] + )] + public function getItemtypes(Request $request): Response + { + return new JSONResponse(PluginDatainjectionInjectionType::getItemtypes()); + } +} diff --git a/inc/backend.class.php b/inc/backend.class.php index b68f4fdf..912953ef 100644 --- a/inc/backend.class.php +++ b/inc/backend.class.php @@ -71,6 +71,7 @@ static function getHeader(PluginDatainjectionData $injectionData, $header_presen * Get the backend implementation by type * * @param $type + * @return PluginDatainjectionBackendInterface **/ static function getInstance($type) { diff --git a/inc/engine.class.php b/inc/engine.class.php index 9a498658..a2081439 100644 --- a/inc/engine.class.php +++ b/inc/engine.class.php @@ -65,8 +65,8 @@ function __construct($model, $infos = [], $entity = 0) { /** * Inject one line of data * - * @param $line one line of data to import - * @param $index the line number is the file + * @param string $line one line of data to import + * @param int $index the line number is the file **/ function injectLine($line, $index) { diff --git a/inc/model.class.php b/inc/model.class.php index 15238352..66d38876 100644 --- a/inc/model.class.php +++ b/inc/model.class.php @@ -932,7 +932,7 @@ function readUploadedFile($options = []) { $file_encoding = (isset($options['file_encoding']) ?$options['file_encoding'] :PluginDatainjectionBackend::ENCODING_AUTO); - $webservice = (isset($options['webservice'])?$options['webservice']:false); + $from_api = (isset($options['from_api'])?$options['from_api']:false); $original_filename = (isset($options['original_filename'])?$options['original_filename']:false); $unique_filename = (isset($options['unique_filename'])?$options['unique_filename']:false); $injectionData = false; @@ -942,7 +942,7 @@ function readUploadedFile($options = []) { //Get model & model specific fields $this->loadSpecificModel(); - if (!$webservice) { + if (!$from_api) { //Get and store uploaded file $original_filename = $_FILES['filename']['name']; $temporary_uploaded_filename = $_FILES["filename"]["tmp_name"]; @@ -961,7 +961,7 @@ function readUploadedFile($options = []) { if ($this->specific_model->checkFileName($original_filename)) { $message = __('File format is wrong', 'datainjection'); $message .= "
".__('Extension csv required', 'datainjection'); - if (!$webservice) { + if (!$from_api) { Session::addMessageAfterRedirect($message, true, ERROR, false); } //unlink($temporary_uniquefilename); @@ -976,8 +976,8 @@ function readUploadedFile($options = []) { $backend->setHeaderPresent($this->specific_model->fields['is_header_present']); $backend->setDelimiter($this->specific_model->fields['delimiter']); - if (!$webservice) { - //Read n line from the CSV file if not webservice + if (!$from_api) { + //Read n line from the CSV file if not from API $injectionData = $backend->read(20); } else { //Read the whole file diff --git a/setup.php b/setup.php index ba1c35a3..69f472e0 100644 --- a/setup.php +++ b/setup.php @@ -79,9 +79,11 @@ function plugin_init_datainjection() { // Javascript file $PLUGIN_HOOKS['add_javascript']['datainjection'] = 'js/datainjection.js'; + $PLUGIN_HOOKS[\Glpi\Plugin\Hooks::API_CONTROLLERS]['datainjection'] = [ + PluginDatainjectionApiController::class + ]; $INJECTABLE_TYPES = []; - } }