From 2b14bbce851578ccca76a6ac1b70035b5daf383b Mon Sep 17 00:00:00 2001 From: Pier Paolo MAMMI Date: Mon, 24 Aug 2026 12:22:32 +0200 Subject: [PATCH] fix save data request --- .../references/protocol.md | 2 +- .../Invoke-ElixFormsSchemaBulkUpdate.ps1 | 65 ++++++++++++------- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/.agents/skills/elixforms-schema-bulk-updater/references/protocol.md b/.agents/skills/elixforms-schema-bulk-updater/references/protocol.md index d3f7472..53fc91f 100644 --- a/.agents/skills/elixforms-schema-bulk-updater/references/protocol.md +++ b/.agents/skills/elixforms-schema-bulk-updater/references/protocol.md @@ -8,7 +8,7 @@ The default base URI is `https://console-unipr.elixforms.it/AJSRV/metadata`. - Search: `GET search?SEARCH_IN[]={schemaId}&S_{schemaId}_NEW_{fieldKey}={value}&PAGE={page}&AJL=it&PAGESIZE=80&SECURE=true` - Save: `POST save` -Send the manually obtained cookie and `X-Requested-With: XMLHttpRequest` on every request. For saves, send one UTF-8 `multipart/form-data` part and an explicit byte-based content length. +Send the manually obtained cookie and `X-Requested-With: XMLHttpRequest` on every request. For saves, send one `multipart/form-data` part through `Invoke-RestMethod` and let it calculate `Content-Length` from the body. ## Ordering and identifiers diff --git a/.agents/skills/elixforms-schema-bulk-updater/scripts/Invoke-ElixFormsSchemaBulkUpdate.ps1 b/.agents/skills/elixforms-schema-bulk-updater/scripts/Invoke-ElixFormsSchemaBulkUpdate.ps1 index d42d5cc..b5102a9 100644 --- a/.agents/skills/elixforms-schema-bulk-updater/scripts/Invoke-ElixFormsSchemaBulkUpdate.ps1 +++ b/.agents/skills/elixforms-schema-bulk-updater/scripts/Invoke-ElixFormsSchemaBulkUpdate.ps1 @@ -40,6 +40,7 @@ param( Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' +Add-Type -AssemblyName System.Net.Http function ConvertTo-QueryString { [CmdletBinding()] @@ -104,13 +105,7 @@ function Invoke-ElixFormsRequest { [Uri] $Uri, [Parameter(Mandatory)] - [string] $Cookie, - - [Parameter()] - [byte[]] $Body, - - [Parameter()] - [string] $ContentType + [string] $Cookie ) $httpMethod = if ($Method -eq 'GET') { [Net.Http.HttpMethod]::Get } else { [Net.Http.HttpMethod]::Post } @@ -123,16 +118,6 @@ function Invoke-ElixFormsRequest { $null = $request.Headers.TryAddWithoutValidation('Origin', $origin) $request.Headers.Referrer = [Uri] ($origin + '/ajconsole/') - if ($PSBoundParameters.ContainsKey('Body')) { - if ([string]::IsNullOrWhiteSpace($ContentType)) { - throw 'ContentType is required when Body is supplied.' - } - - $request.Content = [Net.Http.ByteArrayContent]::new($Body) - $null = $request.Content.Headers.TryAddWithoutValidation('Content-Type', $ContentType) - $request.Content.Headers.ContentLength = $Body.Length - } - try { $response = $Client.SendAsync($request).GetAwaiter().GetResult() try { @@ -185,16 +170,50 @@ function New-MultipartFieldBody { [string] $Value ) - $boundary = '----ElixFormsBoundary' + [Guid]::NewGuid().ToString('N') + $boundary = '---' + [Guid]::NewGuid().ToString('N').Substring(0, 24) $newLine = "`r`n" - $bodyText = '--{0}{1}Content-Disposition: form-data; name="{2}"{1}{1}{3}{1}--{0}--{1}' -f $boundary, $newLine, $Name, $Value - $encoding = [Text.UTF8Encoding]::new($false) - $bytes = $encoding.GetBytes($bodyText) + $body = '--{0}{1}Content-Disposition: form-data; name="{2}"{1}{1}{3}{1}--{0}--{1}' -f $boundary, $newLine, $Name, $Value return [pscustomobject]@{ Boundary = $boundary ContentType = 'multipart/form-data; boundary={0}' -f $boundary - Bytes = $bytes + Body = $body + } +} + +function Invoke-ElixFormsSaveRequest { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [Uri] $Uri, + + [Parameter(Mandatory)] + [string] $Cookie, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $ContentType, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $Body + ) + + $headers = @{} + $headers.Add('Accept', '*/*') + $headers.Add('Accept-Encoding', 'gzip, deflate, br, zstd') + $headers.Add('Cookie', $Cookie) + $headers.Add('x-requested-with', 'XMLHttpRequest') + $headers.Add('Content-Type', $ContentType) + + try { + $response = Invoke-RestMethod -Uri $Uri -Method POST -Headers $headers -ContentType $ContentType -Body $Body -ErrorAction Stop + return [pscustomobject]@{ + Json = $response + } + } + catch { + throw 'Request to {0} failed: {1}' -f $Uri, $_.Exception.Message } } @@ -630,7 +649,7 @@ function Invoke-ElixFormsMetadataBulkUpdate { Write-Host ('[{0}/{1}] Updating object {2} (data ID {3})...' -f ($rowIndex + 1), $search.Rows.Count, $objectId, $dataId) try { - $saveResult = Invoke-ElixFormsRequest -Client $client -Method POST -Uri $saveUri -Cookie $cookie -Body $multipart.Bytes -ContentType $multipart.ContentType + $saveResult = Invoke-ElixFormsSaveRequest -Uri $saveUri -Cookie $cookie -ContentType $multipart.ContentType -Body $multipart.Body $errors = @($saveResult.Json.errors.objectList) $savedObjects = @($saveResult.Json.result.objectList) if ($errors.Count -gt 0 -or $savedObjects.Count -eq 0) {