blog by ficti0n: июня 2020

вторник, 30 июня 2020 г.

Создание заявок в системе GLPI с помощью REST API на Delphi

Для работы понадобилось провести в разрабатываемую программу интеграцию с системой хелпдеска GLPI. Поиск в интернете примеров на Delphi не принес приемлемых результатов и пришлось все писать с нуля. Вот решил поделиться примером создания заявки с прикреплением файла.
P.S. также рекомендую к прочтению вот эту статью, в ней описано GLPI  настраивать для включения REST API

Глобальные переменные и константы:

const
  AppToken = 'hAQiq39NeHWaQ25t6cTkV8762VcHL2Tds7qBuLR4';
  userToken = 'pRHHulWPKXqSrL3xS8vlSCqGIsOu7HWb7rJ3ixI4';

var
  session_token : string;
  GlpiUser, GlpiPassword, GlpiRestUrl : string;

Начинаем все с подключения к GLPI и получения токена сессии:

Function Get_session_token : string;
    var
      IdHTTP: TIdHTTP;
      Answer: string;
      JSON : TJSONObject;
begin
  try

    try
      IdHTTP := TIdHTTP.Create(nil);
      try
        IdHTTP.Request.Connection := 'Keep-Alive';
        Idhttp.HTTPOptions := [hoKeepOrigProtocol,hoForceEncodeParams,hoNoProtocolErrorException,hoWantProtocolErrorContent];
        IdHTTP.Request.ContentType := 'application/json';
        idHttp.Request.BasicAuthentication := true;
        idHttp.Request.Username := GlpiUser;
        idHttp.Request.Password := GlpiPassword;
        IdHTTP.Request.ContentEncoding := 'utf-8';
        IdHTTP.Request.CustomHeaders.Values['Authorization'] :=  'user_token  ' + userToken;
        IdHTTP.Request.CustomHeaders.Values['App-Token'] :=  AppToken;

        Answer := IdHTTP.Get(GlpiRestUrl + '/initSession/');
        JSON := TJSONObject.ParseJSONValue(Answer) as TJSONObject;
        Result := JSON.Get('session_token').JsonValue.Value;

      finally
        IdHTTP.Free;
      end;
    finally

    end;

  except
    on E: Exception do
      ShowMessage('Error: '+E.ToString);
  end;

end;

Также нам понадобиться функция для закрытия сессии:

Function KillSession (sToken: string) : boolean;
    var
      IdHTTP: TIdHTTP;
      Answer: string;
begin
  if sToken = '' then Exit;
  try
    try
      IdHTTP := TIdHTTP.Create(nil);
      try
        IdHTTP.Request.Connection := 'Keep-Alive';
        IdHTTP.Request.ContentType := 'application/json';
        idHttp.Request.BasicAuthentication := true;
        idHttp.Request.Username := GlpiUser;
        idHttp.Request.Password := GlpiPassword;
        IdHTTP.Request.ContentEncoding := 'utf-8';
        IdHTTP.Request.CustomHeaders.Values['Session-Token'] := sToken ;
        IdHTTP.Request.CustomHeaders.Values['App-Token'] :=  AppToken;

        Answer := IdHTTP.Get(GlpiRestUrl + '/killSession/');

        if IdHttp.ResponseCode = 200 then Result := true
                                     else Result := false;

      finally
        IdHTTP.Free;
      end;
    finally

    end;

  except
    on E: Exception do
      ShowMessage('Error: '+E.ToString);
  end;

end;

Ну и сама функция создания заявки с прикреплением файла:

Function CreateTiket (sToken : string): string;
    var
      IdHTTP: TIdHTTP;
      Answer: string;
      JSON, JSON2, JSON3 : TJSONObject;
      JsonToSend: TMemoryStream;
      jsontext : string;
      doc_id, doc_prefix, doc_file : string;
      MultiData : TIdMultiPartFormDataStream;
      JSONArray : TJSONArray;
      newticket_id : string;
begin
  try

    try

     IdHTTP := TIdHTTP.Create(nil);
      try
        IdHTTP.Request.Connection := 'Keep-Alive';
        IdHTTP.Request.ContentType := 'multipart/form-data';     // Это для загрузки документов
        idHttp.Request.BasicAuthentication := true;
        idHttp.Request.Username := GlpiUser;
        idHttp.Request.Password := GlpiPassword;
        Idhttp.Request.AcceptEncoding := 'gzip, identity;q=0';
        IdHttp.Compressor := TIdCompressorZLib.Create(IdHttp);
        Idhttp.Request.Accept := 'application/json';
        Idhttp.HTTPOptions := [hoKeepOrigProtocol,hoForceEncodeParams,hoNoProtocolErrorException,hoWantProtocolErrorContent];
        IdHTTP.Request.ContentEncoding := 'utf-8';
        //Параметр user_token берётся из Ключ удалённого доступа настроек пользователя Администрирование -> Пользователи -> USERNAME -> Настройки
        IdHTTP.Request.CustomHeaders.Values['Authorization'] :=  'user_token  ' + userToken;
        //"Настройки"->"Общие"->"API" и нажав кнопку "Добавить клиента", добавляем запись и генерируем токен (app_token)
        IdHTTP.Request.CustomHeaders.Values['App-Token'] :=  AppToken;
        //"Session-Token" получаем в функции
        IdHTTP.Request.CustomHeaders.Values['Session-Token'] := sToken ;

       //Старт  Загружаем файл
        MultiData := TIdMultiPartFormDataStream.Create;
        MultiData.AddFormField('uploadManifest', '{"input": {"name": "Документ заявки 0000", "_filename" : "DocName", "is_recursive" : true}}', 'utf-8', 'application/json').ContentTransfer := '8bit';
        with MultiData.AddFile('filename[0]','c:\testpicture01.jpg','') do //добавляем файл
          begin
                    HeaderCharset := 'utf-8';
                    HeaderEncoding := '8';
            end;
//Конец  Загружаем файл

        //GlpiRestURL - путь к вашему GLPI. Например 'http://10.0.0.10/glpi/apirest.php';
        Answer := IdHTTP.Post(GlpiRestURL + '/Document/', MultiData);  // отправляем документ

        MultiData.Free;

        //Старт Разбираем полученный ответ
        JSON := TJSONObject.ParseJSONValue(Answer) as TJSONObject;

        doc_id := JSON.Get('id').JsonValue.Value;    // Получаем ID загруженного файла

        JSON2 := TJSONObject(JSON.Get('upload_result').JsonValue);

        JSONArray := TJSONArray(JSON2.Get(0).JsonValue);

        JSON3 := TJSONObject(JSONArray.Get(0));

        doc_file := JSON3.GetValue('name').Value; // Эти значения не нужны, это для примера разбора JSON

        doc_prefix := JSON3.GetValue('prefix').Value; //Эти значения не нужны, это для примера разбора JSON
        //Конец Разбираем полученный ответ

        if (IdHttp.ResponseCode <> 200) and (IdHttp.ResponseCode <> 201)  then Result := 'Ошибка при создании заявки (' + Answer + ')'
                                       else
         begin
             // Старт Отправляем запрос на создание заявки
             IdHTTP.Request.ContentType := 'application/json';    // Это отправки json
              jsontext := '{"input": {"name": "Заявка тестовая", "content": "Описание","status":"1",' +
                '"requesttypes_id":"8","_users_id_assign":"23","time_to_resolve":"2020-06-13 18:00:00",'+
                '"itilcategories_id":"23","urgency":"3","priority":"3"}}';
              JsonToSend := TStringStream.Create(jsontext, TEncoding.UTF8);

              Answer := IdHTTP.Post(GlpiRestURL + '/Ticket', JsonToSend);

              JSON := TJSONObject.ParseJSONValue(Answer) as TJSONObject;

              newticket_id := JSON.Get('id').JsonValue.Value;    //Получяаем ID созданной заявки
              //Конец Отправляем запрос на создание заявки

              // Старт Отправляем запрос на прикрепление файла к заявке
              jsontext := '{"input": {"documents_id" : "' + doc_id + '", "items_id" : "' + newticket_id + '", "itemtype" : "Ticket" }}';
              JsonToSend := TStringStream.Create(jsontext, TEncoding.UTF8);

              Answer := IdHTTP.Post(GlpiRestURL + '/Document_Item', JsonToSend);
              //Конец Отправляем запрос на прикрепление файла к заявке

              Result := 'Заявка создана'
         end;

      finally
        IdHTTP.Free;
      end;
    finally

    end;

  except
    on E: Exception do
      ShowMessage('Error: '+E.ToString);
  end;

end;

Используется например так:

procedure TForm1.Button1Click(Sender: TObject);
Begin
GlpiUser := 'GlpiUsername';
GlpiPassword := 'SuperPassword';
GlpiRestUrl := 'http://10.0.0.10/glpi/apirest.php';
 session_token := Get_session_token;
 ShowMessage(CreateTiket(session_token));
 KillSession(session_token);
end;