You are not logged in.
Je vais tester ça.
Ce serait super que j'arrive à l'intégrer et que ce soit complet...
Merci pour le feedback !
Offline
Pas de quoi j'essaie de trouver tout ce qui pourrait nous aider
Et de notre côté, mon collègue Malory qui essaie de me proposer toutes syntaxes qui s'en rapproche
Ex la il fait dans un fichier :
{
"files": {
"filename[0]": "c:\\temp1\\clear.png"
},
"data": {
"uploadManifest": "{\"input\": {\"name\": \"Uploaded document\", \"tickets_id\": \"161\", \"_filename\" : [\"clear.png\"]}};type"
}
}
$json = (Get-Content "C:\temp1\json.txt").replace("c:\\temp1\\clear.png",$FileContent)
Mais message d'erreur : Surcharge introuvable pour « GetBytes » et le nombre d'arguments « 1 ».
Offline
Hello,
je pêche toujours , il n'y aurait pas un développeur de GLPI dans le coin qui pourrait nous aider ?
En attendant, je pense déjà que dans ta fonction tu peux changer le content-type par multipart/form-data (Si j'ai bien compris ce bout de code dans /inc/api/apirest.class.php)
else if (strpos($content_type, "multipart/form-data") !== false) {
if (count($_FILES) <= 0) {
// likely uploaded files is too big so $_REQUEST will be empty also.
// see http://us.php.net/manual/en/ini.core.php#ini.post-max-size
$this->returnError("The file seems too big", 400,
"ERROR_UPLOAD_FILE_TOO_BIG_POST_MAX_SIZE", false);
}
// with this content_type, php://input is empty... (see http://php.net/manual/en/wrappers.php.php)
if (!$uploadManifest = json_decode(stripcslashes($_REQUEST['uploadManifest']))) {
$this->returnError("JSON payload seems not valid", 400, "ERROR_JSON_PAYLOAD_INVALID",
false);
}
foreach ($uploadManifest as $field => $value) {
$parameters[$field] = $value;
}
$this->format = "json";
// move files into _tmp folder
$parameters['upload_result'] = [];
$parameters['input']->_filename = [];
$parameters['input']->_prefix_filename = [];
}
Et par ailleurs si on obtient l'erreur ERROR_UPLOAD_FILE_TOO_BIG_POST_MAX_SIZE","The file seems too big ça voudrait dire que c'est la variable contenant le nbr de fichier qui ne passe pas genre la
filename= @($FileContent)
Offline
Grâce à Mecmav j'ai pu remarquer que sans le boundary ça ne peux pas passer. Du coup je pense que dans ta fonction en plus du multipart/data à remplacer il faudra :
Déclarer le boundary :
$boundary = [System.Guid]::NewGuid().ToString();
Puis dans le invoke :
-ContentType "multipart/form-data; boundary=$boundary"
concernant le reste (et bien je pêche toujours)
Car dans postman, dans le body il faut 2 KEY :
KEY : uploadManifest
La valeur : {"input":{"name": "Uploading a document","_filename":["test.txt"]}}
KEY : filename
La valeur (bon la on explore le disque pour récupérer le fichier)
Du coup j'ai essayé sans succès :
$File = "C:\Users\Dead-Red\test.txt"
$FileContent = [System.IO.File]::ReadAllBytes("$File ")
$fileEnc = [System.Text.Encoding]::GetEncoding('UTF-8').GetString($FileContent);
$json1=@{}
$json1.uploadManifest= ('{"input":{"name": "Uploading a document","_filename":["test.txt"]}}')
Avec
$file= @{file=(Get-ChildItem $File)}
ou
$file= @{file=($fileEnc)}
ou
$file= @{file=($FileContent)}
ou
$file= @{file=($fileEnc)}
Suite :
$json1.filename=$file
Et aussi avec ces différents body :
$json = $json1
ou
$json = $json1 | ConvertTo-Json
ou
$json = @($json1 | ConvertTo-Json)
Et ces différentes commandes :
Invoke-RestMethod "$AppURL/$($SubItemType)" -Method Post -Headers @{"session-token"=$SessionToken.session_token; "content-type"="multipart/form-data"; "App-Token" = $AppToken; "Accept"='*/*'} -Body ([System.Text.Encoding]::UTF8.GetBytes($json)) -ContentType "multipart/form-data; boundary=$boundary"
Invoke-RestMethod "$AppURL/$($SubItemType)" -Method Post -Headers @{"session-token"=$SessionToken.session_token; "content-type"="multipart/form-data"; "App-Token" = $AppToken; "Accept"='*/*'} -Body ([System.Text.Encoding]::UTF8.GetBytes($json)) -ContentType "multipart/form-data; boundary=$boundary"
Invoke-RestMethod "$AppURL/$($SubItemType)" -Method Post -Headers @{"session-token"=$SessionToken.session_token; "content-type"="multipart/form-data"; "App-Token" = $AppToken; "Accept"='*/*'} -Body ([System.Text.Encoding]::UTF8.GetBytes($json))
Invoke-RestMethod "$AppURL/$($SubItemType)" -Method Post -Headers @{"session-token"=$SessionToken.session_token; "content-type"="multipart/form-data"; "App-Token" = $AppToken; "Accept"='*/*'} -Body ($json) -ContentType "multipart/form-data; boundary=$boundary"
Offline
Je n'arrive pas à le faire fonctionner, mais le code envoyé par Postman (qui lui envoi bien le fichier sur le glpi) peut être transformé en powershell.
Même si moi ça ne marche pas peut être que ... :
Voici le code :
Add-Type -AssemblyName System.Net.Http
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("App-Token", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
$headers.Add("session-token", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
$headers.Add("Authorization", "Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
$multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
$stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$stringHeader.Name = "uploadManifest"
$stringContent = [System.Net.Http.StringContent]::new("{`"input`":{`"name`": `"Uploading a document`",`"_filename`":[`"test.txt`"]}}")
$stringContent.Headers.ContentDisposition = $stringHeader
$multipartContent.Add($stringContent)
$multipartFile = 'C:\Users\Dead-Red\test.txt'
$FileStream = [System.IO.FileStream]::new($multipartFile, [System.IO.FileMode]::Open)
$fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$fileHeader.Name = "filename"
$fileHeader.FileName = ""
$fileContent = [System.Net.Http.StreamContent]::new($FileStream)
$fileContent.Headers.ContentDisposition = $fileHeader
$multipartContent.Add($fileContent)
$body = $multipartContent
$response = Invoke-RestMethod 'XXXXXXX/apirest.php/Document/' -Method 'POST' -Headers $headers -Body $body
$response | ConvertTo-Json
$filestream.Close()
Peut être en powershell v7 (si quelqu'un passe par là) ? (je préfère rester en 5.1 pour ma part, afin d'être au plus proche des utilisateurs)
Last edited by Dead-Red (2021-04-20 13:34:32)
Offline
Je reçois un vilain "ERROR_BAD_ARRAY" en utilisant le code fourni par PostMan :-(
Offline
Pareil.
Et le support de GLPI ne sont pas d'une grande aide.
Hi,
If it works using Postman, then there is no bug on GLPI side.
To get support, you can ask for community support on forum or get a subscription for a professionnal support.
I close this issue as it is not a bug.
Regards
Source : GITHUB/glpi-project/glpi/issues/8967
Alors qu'ils ont bien plus de compétences pour savoir ce qui est erroné dans la donnée attendue. ;(
Offline
Je ne suis pas surpris :-)
Offline
Ce serait possible d'avoir la config de PostMan, que je puisse reproduire l'upload ici ?
Offline
Yes, je vais récup les infos de mecmav (pour permettre le copier-coller) + les screens
Last edited by Dead-Red (2021-04-20 13:37:37)
Offline
Alors pour permettre de faire depuis postman :
Perso directement dans le Projet, j'ai créé mes variables avec leur valeur respective :
GLPI_App-Token
GLPI_UserToken
GLPI_AppURL
GLPI_SessionToken
Puis ensuite j'ai créé une requête GET (nomée initSession) qui vient mettre à jour la variable GLPI_SessionToken
La requête GET :
Dans le Headers j'ai :
App-Token = {{GLPI_App-Token}}
Authorization = user_token {{GLPI_UserToken}}
Puis après dans la rubrique Tests j'ai ajouté :
pm.test('Status code is 200', function () {
pm.response.to.have.status(200);
});
var jsonBody = pm.response.json();
pm.collectionVariables.set("GLPI_SessionToken",jsonBody.session_token);
Ce qui fait qu'avant de commencer à faire d'autres requêtes, je lance celle-ci, elle vient mettre à jour la variable "d'environnement" et j'utilise la variable d'env dans mes autres requêtes.
Donc pour la requête de POST de fichier dans le header :
Il faut faire afficher les headers masqué. Il ne faut que les headers App-Token & session-token à rentrer à la mano (bien que je crois que le APP-TOKEN n'est pas utile)
Ensuite dans body :
il faut créer la KEY : uploadManifest et saisir le code suivant :
{"input":{"name": "Uploading a document","_filename":["test.txt"]}}
la deuxième KEY il faut remplacer le "format" text par file et allez chercher le fichier.
Merci à MecMav / Thank's you MecMav
Last edited by Dead-Red (2021-04-20 13:59:59)
Offline
Je vais tester ça. Merci à vous deux
Offline
Salut!
Puis-je utiliser ce module pour ajouter plusieurs ProjectTask pour un Project donné ?
Merci
Offline
Bonjour,
Oui, il n'y a pas de raison :-)
Offline
Bonsoir,
j'ai eu le même problème d'upload de document via PowerApps et le secret est de convertir le document en base64 voici un exemple qui fonctionne :
{
"$content-type": "multipart/form-data",
"$multipart": [
{
"headers": {
"Content-Disposition": "form-data; name=\"uploadManifest\""
},
"body": {
"$content": {
"input": {
"name": "test.pdf",
"_filename": [
"test.pdf"
]
}
}
}
},
{
"body": {
"$content": "JVBERi0xLjQKJdP0zOE ------ LE DOCUMENT EN BASE 64 ICI ------ OQolJUVPRgo=",
"$content-type": "application/pdf"
},
"headers": {
"Content-Disposition": "form-data; name=\"file\"; filename=\"test.pdf\""
}
}
]
}
Offline
en python cela donnerai ceci :
import requests
url = 'https://domaine.com/apirest.php/Document/' # Remplacez par l'URL de votre choix
# Définissez le contenu du manifeste
manifest_content = {
"input": {
"name": "test.pdf",
"_filename": [
"test.pdf"
]
}
}
# Définissez le contenu du fichier
file_content = "JVBERi0xLjQKJdP0zOE ------ LE DOCUMENT EN BASE 64 ICI ------ OQolJUVPRgo=" # Remplacez par le contenu de votre fichier en base64
# Créez les données multipart
multipart_data = {
'uploadManifest': ('manifest.json', json.dumps(manifest_content), 'application/json'),
'file': ('test.pdf', base64.b64decode(file_content), 'application/pdf'),
}
response = requests.post(url, files=multipart_data)
# Vérifiez la réponse
if response.status_code == 200:
print("Le fichier a été téléchargé avec succès.")
else:
print(f"Erreur lors du téléchargement du fichier: {response.status_code}")
Offline
Bonjour Bastien,
merci de ton retour et de ton aide. Mais je n'arrive pas pour autant à faire fonctionner.
Aurais-tu le code powershell complet qui upload un document ?
Merci par avance
Offline
Bonjour à tous !
J'ai enfin réussi à trouver le code nécessaire pour l'upload de fichier vers GLPI.
J'épure mon fichier de test (qui est très très à vomir), je remet en forme et je publie le code
Offline
Bonjour à tous,
@Dead-Red ça fait depuis le début de semaine que je m'arrache les cheveux pour uploader des fichiers sur GLPI via l'API, j'ai suivi toutes tes recherches !
J'ai finalement réussi bêtement en exportant le code de Postman dans une session Powershell 7, mais je suis curieux de savoir comment toi tu as réussi (si c'est en version 5)
function Upload-GLPI-File{
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("session-token", "SESSION TOKEN")
$headers.Add("app-token", "APP TOKEN")
$multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
$stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$stringHeader.Name = "uploadManifest"
$stringContent = [System.Net.Http.StringContent]::new("{`"input`":{`"_filename`":`"[NOM DU FICHIER]`",`"name`":`"NOM DU FICHIER`"}}")
$stringContent.Headers.ContentDisposition = $stringHeader
$multipartContent.Add($stringContent)
$multipartFile = "CHEMIN DU FICHIER"
$FileStream = [System.IO.FileStream]::new($multipartFile, [System.IO.FileMode]::Open)
$fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$fileHeader.Name = "filename"
$fileHeader.FileName = "CHEMIN DU FICHIER"
$fileContent = [System.Net.Http.StreamContent]::new($FileStream)
$fileContent.Headers.ContentDisposition = $fileHeader
$multipartContent.Add($fileContent)
$body = $multipartContent
$global:glpifileid = Invoke-RestMethod '**URLGLPI**/Document' -Method 'POST' -Headers $headers -Body $body
$filestream.close()
En bonus ci-dessous pour assigner le document au ticket :
function Attach-DocumentToTicket{
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("session-token", "SESSION TOKEN")
$headers.Add("app-token", "APP TOKEN")
$headers.Add("Content-Type", "application/json")
$body = @"
{
`"input`":{
`"documents_id`": `"ID DOCUMENT`",
`"items_id`": `"ID TICKET`",
`"itemtype`": `"Ticket`"
}
}
"@
Invoke-RestMethod '**GLPI URL**/Document/1/Document_Item/' -Method 'POST' -Headers $headers -Body $body
}
@++
Offline
Effectivement je voulais absolument que ça fonctionne sur la version 5.1 (d'ailleurs si tu sais tester sur la 7 et me dire )
Voici le code
(Il faut encore l'épurer et le rendre plus propre mais au moins il marche) :
$AppToken = "XXXXXXXXXXXXXXXXXXXXX"
$session_token = "XXXXXXXXXXXXXXXXXXXXX"
# Chemin du fichier à uploader
$FilePath = "C:\TEMP\GLPI_DOCS\test2.pdf"
$fileName = $FilePath.Split('\')[-1]
# Définition de l'URL de l'API GLPI
$url = "https://URL-GLPI/apirest.php/Document/" # Remplacez par l'URL de votre choix
# Lecture du contenu du fichier et conversion en base64
$TheFile = [System.IO.File]::ReadAllBytes($FilePath)
$fileContentBase64 = [System.Text.Encoding]::GetEncoding('iso-8859-1').GetString($TheFile)
# Définition du contenu du manifeste
$manifestContent = @{
"input" = @{
"name" = $fileName
"_filename" = @($fileName)
"entities_id" = 32
}
} | ConvertTo-Json
# Création des données multipart
$boundary = [System.Guid]::NewGuid().ToString()
$multipartData = @"
--$boundary
Content-Disposition: form-data; name="uploadManifest"
$manifestContent
--$boundary
Content-Disposition: form-data; name="filename[0]"; filename="$fileName"
Content-Type: application/octet-stream
$fileContentBase64
--$boundary--
"@
# Définition des en-têtes de la requête
$headers = @{
"App-Token" = $AppToken
"session-token" = $session_token
}
Invoke-RestMethod -Uri $url -Method POST -Headers $headers -ContentType "multipart/form-data; boundary=$boundary" -Body $multipartData
Offline