Merge branch 'main' into script-autogenerate-http
This commit is contained in:
@@ -5,78 +5,10 @@ info:
|
|||||||
|
|
||||||
http:
|
http:
|
||||||
method: GET
|
method: GET
|
||||||
url: "{{IrisApiUrl}}/contracts;full?pid=VERO_L_26_CRCT_RA_AOUPR_01"
|
url: "{{IrisApiUrl}}/contracts;full?pid=SEGA_A_25_FORM_COM_01"
|
||||||
params:
|
params:
|
||||||
- name: pid
|
- name: pid
|
||||||
value: BELL_B_25_CCS_IST_RA_01
|
value: SEGA_A_25_FORM_COM_01
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: VIGN_G_25_CCS_COM_RA_FMT_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: BETT_S_25_CRCT_RA_CHIESI_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: BUSC_A_25_CRCT_RA_IRENAMBIENTE_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: RICC_A_25_CRCT_RA_KEMIN_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: GOBB_G_25_CONV_QUA_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: DELM_N_25_CRCT_RA_BAUMER_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: AMER_F_25_CCS_IST_RA_CODICI_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: wfState
|
|
||||||
value: validated
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: page
|
|
||||||
value: "1"
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: year
|
|
||||||
value: "2025"
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: MAMB_C_25_ACC_ACC_PROROGACONTRATTOCATAGLOGAZIO_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: ZERB_A_25_SERV_CON_ASSUNTA_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: COVA_P_24_SERV_CON_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: GIUL_F_25_CRCT_RA_MOVYON_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: LONG_S_25_SERV_CON_POLIMI_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: DONO_G_25_ACC_ACC_ZOETIS_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: VERO_L_26_CRCT_RA_AOUPR_01
|
|
||||||
type: query
|
type: query
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
@@ -2192,3 +2124,27 @@ examples:
|
|||||||
body:
|
body:
|
||||||
type: json
|
type: json
|
||||||
data: "[]"
|
data: "[]"
|
||||||
|
|
||||||
|
docs: |
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
| name | value | note |
|
||||||
|
| ---- | ------------------------------------------------- | ----------------------- |
|
||||||
|
| pid | BELL_B_25_CCS_IST_RA_01 | |
|
||||||
|
| pid | VIGN_G_25_CCS_COM_RA_FMT_01 | |
|
||||||
|
| pid | BETT_S_25_CRCT_RA_CHIESI_01 | |
|
||||||
|
| pid | BUSC_A_25_CRCT_RA_IRENAMBIENTE_01 | |
|
||||||
|
| pid | RICC_A_25_CRCT_RA_KEMIN_01 | |
|
||||||
|
| pid | GOBB_G_25_CONV_QUA_01 | |
|
||||||
|
| pid | DELM_N_25_CRCT_RA_BAUMER_01 | |
|
||||||
|
| pid | AMER_F_25_CCS_IST_RA_CODICI_01 | |
|
||||||
|
| pid | MAMB_C_25_ACC_ACC_PROROGACONTRATTOCATAGLOGAZIO_01 | |
|
||||||
|
| pid | ZERB_A_25_SERV_CON_ASSUNTA_01 | |
|
||||||
|
| pid | COVA_P_24_SERV_CON_01 | |
|
||||||
|
| pid | GIUL_F_25_CRCT_RA_MOVYON_01 | |
|
||||||
|
| pid | LONG_S_25_SERV_CON_POLIMI_01 | |
|
||||||
|
| pid | DONO_G_25_ACC_ACC_ZOETIS_01 | |
|
||||||
|
| pid | VERO_L_26_CRCT_RA_AOUPR_01 | |
|
||||||
|
| pid | SEGA_A_25_FORM_COM_01 | |
|
||||||
|
| pid | BELL_B_26_CCS_IST_RA_AGENZIAREGIONALEPERLASICU_01 | 4 owner + 3 contributor |
|
||||||
|
| pid | GIUL_F_25_CRCT_RA_MOVYON_01 | 2 owner + 7 contributor |
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ info:
|
|||||||
|
|
||||||
http:
|
http:
|
||||||
method: GET
|
method: GET
|
||||||
url: "{{IrisApiUrl}}/contracts?page={{currentPage}}&sort=pid&dir=asc&wfState=closed&wfState=signed"
|
url: "{{IrisApiUrl}}/contracts?person.cf=GLNFLC70S16I158E&person.relation=contributor&page={{currentPage}}&pageSize=20&sort=pid&dir=asc"
|
||||||
params:
|
params:
|
||||||
- name: id
|
- name: id
|
||||||
value: "123"
|
value: "123"
|
||||||
@@ -48,6 +48,9 @@ http:
|
|||||||
value: ""
|
value: ""
|
||||||
type: query
|
type: query
|
||||||
disabled: true
|
disabled: true
|
||||||
|
- name: person.cf
|
||||||
|
value: GLNFLC70S16I158E
|
||||||
|
type: query
|
||||||
- name: person.id
|
- name: person.id
|
||||||
value: ""
|
value: ""
|
||||||
type: query
|
type: query
|
||||||
@@ -69,10 +72,9 @@ http:
|
|||||||
type: query
|
type: query
|
||||||
disabled: true
|
disabled: true
|
||||||
- name: person.relation
|
- name: person.relation
|
||||||
value: test
|
value: contributor
|
||||||
type: query
|
type: query
|
||||||
description: owner|contributor
|
description: owner|contributor
|
||||||
disabled: true
|
|
||||||
- name: department.id
|
- name: department.id
|
||||||
value: ""
|
value: ""
|
||||||
type: query
|
type: query
|
||||||
@@ -108,6 +110,9 @@ http:
|
|||||||
- name: page
|
- name: page
|
||||||
value: "{{currentPage}}"
|
value: "{{currentPage}}"
|
||||||
type: query
|
type: query
|
||||||
|
- name: pageSize
|
||||||
|
value: "20"
|
||||||
|
type: query
|
||||||
- name: sort
|
- name: sort
|
||||||
value: pid
|
value: pid
|
||||||
type: query
|
type: query
|
||||||
@@ -117,9 +122,11 @@ http:
|
|||||||
- name: wfState
|
- name: wfState
|
||||||
value: closed
|
value: closed
|
||||||
type: query
|
type: query
|
||||||
|
disabled: true
|
||||||
- name: wfState
|
- name: wfState
|
||||||
value: signed
|
value: signed
|
||||||
type: query
|
type: query
|
||||||
|
disabled: true
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
|
|||||||
+17
-36
@@ -1,52 +1,22 @@
|
|||||||
info:
|
info:
|
||||||
name: Get Contracts with two or more participants (scripted)
|
name: SCRIPT - Get Contracts with two or more contributors
|
||||||
type: http
|
type: http
|
||||||
seq: 4
|
seq: 5
|
||||||
|
|
||||||
http:
|
http:
|
||||||
method: GET
|
method: GET
|
||||||
url: "{{IrisApiUrl}}/contracts;full?year=2025&wfState=signed&page=1"
|
url: "{{IrisApiUrl}}/contracts;full?year=2026"
|
||||||
params:
|
params:
|
||||||
- name: year
|
- name: year
|
||||||
value: "2025"
|
value: "2026"
|
||||||
type: query
|
type: query
|
||||||
- name: wfState
|
- name: wfState
|
||||||
value: signed
|
value: signed
|
||||||
type: query
|
type: query
|
||||||
|
disabled: true
|
||||||
- name: page
|
- name: page
|
||||||
value: "1"
|
value: "1"
|
||||||
type: query
|
type: query
|
||||||
- name: pid
|
|
||||||
value: BELL_B_25_CCS_IST_RA_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: VIGN_G_25_CCS_COM_RA_FMT_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: BETT_S_25_CRCT_RA_CHIESI_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: BUSC_A_25_CRCT_RA_IRENAMBIENTE_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: RICC_A_25_CRCT_RA_KEMIN_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: GOBB_G_25_CONV_QUA_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: DELM_N_25_CRCT_RA_BAUMER_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
|
||||||
- name: pid
|
|
||||||
value: AMER_F_25_CCS_IST_RA_CODICI_01
|
|
||||||
type: query
|
|
||||||
disabled: true
|
disabled: true
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
@@ -204,7 +174,7 @@ runtime:
|
|||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
//console.log("Setting current page to: " + n);
|
//console.log("Setting current page to: " + n);
|
||||||
const nextUrl = setQueryObject(req.getUrl(), { [PAGE_PARAM]: String(n) });
|
const nextUrl = setQueryObject(req.getUrl(), { [PAGE_PARAM]: String(n) });
|
||||||
const reqHeaders = req.getHeaders
|
const reqHeaders = req.getHeaders();
|
||||||
|
|
||||||
console.log("Setting headers: " + JSON.stringify(reqHeaders));
|
console.log("Setting headers: " + JSON.stringify(reqHeaders));
|
||||||
setTimeout(async function () {
|
setTimeout(async function () {
|
||||||
@@ -255,6 +225,8 @@ runtime:
|
|||||||
// Save to environment
|
// Save to environment
|
||||||
bru.setVar(TARGET_ENV_VAR, JSON.stringify(output));
|
bru.setVar(TARGET_ENV_VAR, JSON.stringify(output));
|
||||||
|
|
||||||
|
console.log(JSON.stringify(output));
|
||||||
|
|
||||||
// Basic summary tests
|
// Basic summary tests
|
||||||
test('Aggregated items have required properties', function () {
|
test('Aggregated items have required properties', function () {
|
||||||
output.forEach(item => {
|
output.forEach(item => {
|
||||||
@@ -275,6 +247,15 @@ runtime:
|
|||||||
|
|
||||||
run();
|
run();
|
||||||
})();
|
})();
|
||||||
|
actions:
|
||||||
|
- type: set-variable
|
||||||
|
phase: after-response
|
||||||
|
selector:
|
||||||
|
expression: ""
|
||||||
|
method: jsonq
|
||||||
|
variable:
|
||||||
|
name: multiContributorContracts
|
||||||
|
scope: runtime
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
encodeUrl: true
|
encodeUrl: true
|
||||||
+278
@@ -0,0 +1,278 @@
|
|||||||
|
info:
|
||||||
|
name: SCRIPT - Get Contracts with two or more owners
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: "{{IrisApiUrl}}/contracts?year=2026"
|
||||||
|
params:
|
||||||
|
- name: year
|
||||||
|
value: "2026"
|
||||||
|
type: query
|
||||||
|
- name: wfState
|
||||||
|
value: signed
|
||||||
|
type: query
|
||||||
|
disabled: true
|
||||||
|
- name: page
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
disabled: true
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
runtime:
|
||||||
|
scripts:
|
||||||
|
- type: after-response
|
||||||
|
code: |-
|
||||||
|
// Aggregates contracts with 2+ contributors across all pages and reports summary.
|
||||||
|
// // Fixes TypeError: pm.request.url.query.toObject(...).find is not a function by avoiding Array.prototype.find on toObject() result.
|
||||||
|
// Adds robust helpers for working with query params across Postman SDK versions and edge cases.
|
||||||
|
//
|
||||||
|
// Requirements addressed:
|
||||||
|
// 1) Read Page-Count header to know total pages
|
||||||
|
// 2) Iteratively call same endpoint for pages from current+1 to Page-Count, preserving other query params
|
||||||
|
// 3) Aggregate items where contributorSet exists and has length >= 2
|
||||||
|
// 4) Build a map pid -> contributorCount across all pages (including initial)
|
||||||
|
// 5) Print summary in Test Results and set env var `multiContributorContracts` with [{ pid, contributorCount }]
|
||||||
|
// 6) Robust error handling, rate limiting, early stop on non-2xx; handle JSON array or paginated object response shapes
|
||||||
|
// 7) Augment aggregation with department (ownerSet[0].organizationUnit.idAb + " - " + description). Keep first non-empty.
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
const RATE_LIMIT_DELAY_MS = 200; // small delay between page fetches
|
||||||
|
const TARGET_ENV_VAR = 'multiOwnerContracts';
|
||||||
|
const PAGE_PARAM = 'page';
|
||||||
|
|
||||||
|
// ---------------- URL and Query helpers (SDK-safe) -----------------
|
||||||
|
// Returns a plain object of query params. Works with:
|
||||||
|
// - pm.request.url.query (SDK v8+ as QueryList) using .toObject()
|
||||||
|
// - URL that has no query or is a raw string
|
||||||
|
function getQueryObject(url) {
|
||||||
|
try {
|
||||||
|
// // pm.request.url can be a Url object or a string. Normalize to raw string.
|
||||||
|
const raw = (typeof url === 'string') ? url : (url && (url.toString ? url.toString() : url.raw || ''));
|
||||||
|
// Try SDK path first if it's a Url object with .query
|
||||||
|
if (url && url.query && typeof url.query.toObject === 'function') {
|
||||||
|
const obj = url.query.toObject();
|
||||||
|
// toObject may return undefined/null on empty query
|
||||||
|
return obj && typeof obj === 'object' ? { ...obj } : {};
|
||||||
|
}
|
||||||
|
// Fallback: parse the raw string
|
||||||
|
if (typeof raw === 'string') {
|
||||||
|
const qIndex = raw.indexOf('?');
|
||||||
|
if (qIndex === -1) return {};
|
||||||
|
const queryStr = raw.substring(qIndex + 1);
|
||||||
|
if (!queryStr) return {};
|
||||||
|
return queryStr.split('&').reduce((acc, pair) => {
|
||||||
|
if (!pair) return acc;
|
||||||
|
const [k, v] = pair.split('=');
|
||||||
|
if (!k) return acc;
|
||||||
|
acc[decodeURIComponent(k)] = v !== undefined ? decodeURIComponent(v) : '';
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// fallthrough
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setQueryObject(url, updates) {
|
||||||
|
// Returns a new raw URL string with given query params merged
|
||||||
|
const raw = (typeof url === 'string') ? url : (url && (url.toString ? url.toString() : url.raw || ''));
|
||||||
|
const qIndex = raw.indexOf('?');
|
||||||
|
const base = qIndex === -1 ? raw : raw.substring(0, qIndex);
|
||||||
|
const current = getQueryObject(url);
|
||||||
|
const merged = { ...current, ...updates };
|
||||||
|
// Filter out empty/undefined to avoid adding stray keys
|
||||||
|
const parts = Object.keys(merged)
|
||||||
|
.filter(k => merged[k] !== undefined && merged[k] !== null && merged[k] !== '')
|
||||||
|
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(String(merged[k])));
|
||||||
|
return parts.length ? base + '?' + parts.join('&') : base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- Response shape helpers -----------------
|
||||||
|
function isObject(x) { return x && typeof x === 'object' && !Array.isArray(x); }
|
||||||
|
|
||||||
|
function getItemsFromResponseBody(rb) {
|
||||||
|
// Supports either an array payload or an object with an array at known keys
|
||||||
|
if (Array.isArray(rb)) return rb;
|
||||||
|
if (isObject(rb)) {
|
||||||
|
// Try common keys: 'items', 'data', 'results'
|
||||||
|
if (Array.isArray(rb.items)) return rb.items;
|
||||||
|
if (Array.isArray(rb.data)) return rb.data;
|
||||||
|
if (Array.isArray(rb.results)) return rb.results;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeJson(body) {
|
||||||
|
try { return JSON.parse(body); } catch (e) { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- Aggregation store -----------------
|
||||||
|
// Map: pid -> { contributorCount, department }
|
||||||
|
const aggregate = {};
|
||||||
|
|
||||||
|
function extractDepartment(item) {
|
||||||
|
try {
|
||||||
|
const owner0 = Array.isArray(item.ownerSet) && item.ownerSet.length > 0 ? item.ownerSet[0] : null;
|
||||||
|
const ou = owner0 && owner0.organizationUnit ? owner0.organizationUnit : null;
|
||||||
|
const idAb = ou && typeof ou.idAb === 'string' ? ou.idAb : null;
|
||||||
|
const desc = ou && typeof ou.description === 'string' ? ou.description : null;
|
||||||
|
if (idAb && desc) return idAb + ' - ' + desc;
|
||||||
|
return '';
|
||||||
|
} catch (e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function considerItems(items) {
|
||||||
|
items.forEach(it => {
|
||||||
|
const owners = Array.isArray(it.ownerSet) ? it.ownerSet : [];
|
||||||
|
if (owners.length >= 2) {
|
||||||
|
const pid = (it.pid != null) ? String(it.pid) : '';
|
||||||
|
if (!pid) return;
|
||||||
|
const ownersCount = owners.length;
|
||||||
|
if (!aggregate[pid]) {
|
||||||
|
aggregate[pid] = { ownersCount: ownersCount };
|
||||||
|
} else {
|
||||||
|
// keep max owner count seen (in case of variations) and first non-empty department
|
||||||
|
aggregate[pid].ownersCount = Math.max(aggregate[pid].ownersCount, ownersCount);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
const contributorCount = contributors.length;
|
||||||
|
const dept = extractDepartment(it);
|
||||||
|
if (!aggregate[pid]) {
|
||||||
|
aggregate[pid] = { contributorCount, department: dept || '' };
|
||||||
|
} else {
|
||||||
|
// keep max contributor count seen (in case of variations) and first non-empty department
|
||||||
|
aggregate[pid].contributorCount = Math.max(aggregate[pid].contributorCount, contributorCount);
|
||||||
|
if (!aggregate[pid].department && dept) {
|
||||||
|
aggregate[pid].department = dept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- Paging orchestration -----------------
|
||||||
|
const initialStatus = res.getStatus();
|
||||||
|
const is2xx = initialStatus >= 200 && initialStatus < 300;
|
||||||
|
if (!is2xx) {
|
||||||
|
test('Request failed - not aggregating on non-2xx', function () {
|
||||||
|
expect(is2xx).to.eql(true);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rb = safeJson(JSON.stringify(res.getBody()));
|
||||||
|
const initialItems = rb ? getItemsFromResponseBody(rb) : [];
|
||||||
|
considerItems(initialItems);
|
||||||
|
|
||||||
|
// Derive total pages from header 'Page-Count' or 'page-count'
|
||||||
|
const pageCountHeader = res.getHeader('Page-Count') || res.getHeader('page-count') || res.getHeader('X-Total-Pages');
|
||||||
|
const totalPages = pageCountHeader ? parseInt(pageCountHeader, 10) : 1;
|
||||||
|
|
||||||
|
// Figure out current page from request URL (query param 'page')
|
||||||
|
const currentQuery = getQueryObject(req.getUrl());
|
||||||
|
const currentPage = parseInt(currentQuery[PAGE_PARAM] || '1', 10) || 1;
|
||||||
|
|
||||||
|
// Build a function that fetches page N and aggregates
|
||||||
|
function fetchPage(n) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
//console.log("Setting current page to: " + n);
|
||||||
|
const nextUrl = setQueryObject(req.getUrl(), { [PAGE_PARAM]: String(n) });
|
||||||
|
const reqHeaders = req.getHeaders();
|
||||||
|
|
||||||
|
console.log("Setting headers: " + JSON.stringify(reqHeaders));
|
||||||
|
setTimeout(async function () {
|
||||||
|
console.log("Calling next URL... (" + nextUrl + ")");
|
||||||
|
await bru.sendRequest({ url: nextUrl, method: 'GET', headers: reqHeaders }, async function(err, res) {
|
||||||
|
if (err || !res) {
|
||||||
|
console.log("Error fetching page " + n + " (err: " + JSON.stringify(err) + ")");
|
||||||
|
test('Error fetching page ' + n, function () {
|
||||||
|
expect(err).to.eql(null);
|
||||||
|
});
|
||||||
|
return resolve(false);
|
||||||
|
}
|
||||||
|
const ok = res.status >= 200 && res.status < 300;
|
||||||
|
console.log("Next URL response: " + ok);
|
||||||
|
if (!ok) {
|
||||||
|
test('Non-2xx on page ' + n + ' - stop further paging', function () {
|
||||||
|
expect(ok).to.eql(true);
|
||||||
|
});
|
||||||
|
return resolve(false);
|
||||||
|
}
|
||||||
|
const body = res.data;
|
||||||
|
const json = safeJson(body);
|
||||||
|
const items = json ? getItemsFromResponseBody(json) : [];
|
||||||
|
considerItems(items);
|
||||||
|
return resolve(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
}, RATE_LIMIT_DELAY_MS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
console.log("Running...");
|
||||||
|
console.log("Total pages found: " + totalPages);
|
||||||
|
// If there are more pages, iterate
|
||||||
|
for (let p = currentPage + 1; p <= totalPages; p++) {
|
||||||
|
const cont = await fetchPage(p);
|
||||||
|
if (!cont) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare output array
|
||||||
|
const output = Object.keys(aggregate).map(pid => ({
|
||||||
|
pid,
|
||||||
|
ownersCount: aggregate[pid].ownersCount
|
||||||
|
/*
|
||||||
|
contributorCount: aggregate[pid].contributorCount,
|
||||||
|
department: aggregate[pid].department || ''
|
||||||
|
*/
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Save to environment
|
||||||
|
bru.setVar(TARGET_ENV_VAR, JSON.stringify(output));
|
||||||
|
|
||||||
|
console.log(JSON.stringify(output));
|
||||||
|
|
||||||
|
// Basic summary tests
|
||||||
|
test('Aggregated items have required properties', function () {
|
||||||
|
output.forEach(item => {
|
||||||
|
expect(item).to.have.property('pid');
|
||||||
|
expect(item.pid).to.be.a('string');
|
||||||
|
expect(item).to.have.property('ownersCount');
|
||||||
|
expect(item.contributorCount).to.be.a('number');
|
||||||
|
/*
|
||||||
|
expect(item).to.have.property('department');
|
||||||
|
expect(item.department).to.be.a('string');
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Optional: Log summary count
|
||||||
|
test('Total multi-contributor contracts aggregated', function () {
|
||||||
|
expect(output.length).to.be.at.least(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
})();
|
||||||
|
actions:
|
||||||
|
- type: set-variable
|
||||||
|
phase: after-response
|
||||||
|
selector:
|
||||||
|
expression: ""
|
||||||
|
method: jsonq
|
||||||
|
variable:
|
||||||
|
name: multiOwnerContracts
|
||||||
|
scope: runtime
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
@@ -5,3 +5,14 @@ info:
|
|||||||
|
|
||||||
request:
|
request:
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
|
docs:
|
||||||
|
content: |-
|
||||||
|
# IRIS GW (Gateway) REST API documentation (v1)
|
||||||
|
|
||||||
|
Link: <https://air.unipr.it/sr/doc/rest/gw-rest-api.jsp>
|
||||||
|
|
||||||
|
## Contratti
|
||||||
|
|
||||||
|
Link: <https://air.unipr.it/sr/doc/rest/gw-rest-api.jsp#contracts>
|
||||||
|
type: text/markdown
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
info:
|
||||||
|
name: Test Remote WS
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: https://console-unipr.elixforms.it//eF/api/remote/www-idem-unipr-it/ws-elix-progetti__pj.php/v1
|
||||||
|
headers:
|
||||||
|
- name: x-requested-with
|
||||||
|
value: XMLHttpRequest
|
||||||
|
body:
|
||||||
|
type: form-urlencoded
|
||||||
|
data:
|
||||||
|
- name: username
|
||||||
|
value: "{{elixFormsApiUsername}}"
|
||||||
|
- name: requestStatus
|
||||||
|
value: ""
|
||||||
|
description: "nuovo stato della request, possibili valori: SUBMITTED, PROCESSED"
|
||||||
|
disabled: true
|
||||||
|
- name: swfOptionKey
|
||||||
|
value: ""
|
||||||
|
description: |-
|
||||||
|
indice del valore associato al SWF che si desidera impostare
|
||||||
|
|
||||||
|
più chiaramente, si suppone che il modulo associato alla richiesta abbia un SWF impostato, cioè avente degli stati personalizzati, e che esista un campo SELECT contenente tali stati: il valore indicato da questo parametro è l'indice (base 1) del nuovo stato personalizzato che si vuole impostare
|
||||||
|
disabled: true
|
||||||
|
- name: properties
|
||||||
|
value: '[{"key":"COL0004","value":"cambio stato manuale"},{"key":"COL0002","value":"31-03-2025"}]'
|
||||||
|
description: |-
|
||||||
|
mappa chiave,valore/i aggiuntivo/i in formato json (url-encoding richiesto in UTF-8)
|
||||||
|
|
||||||
|
il formato è del tipo: `[{"key":"COL0004","value":"cambio stato manuale"},{"key":"COL0002","value":"31-03-2025"}]`
|
||||||
|
disabled: true
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
info:
|
info:
|
||||||
name: _HACKS
|
name: _HACKS
|
||||||
type: folder
|
type: folder
|
||||||
seq: 4
|
seq: 3
|
||||||
|
|
||||||
request:
|
request:
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|||||||
Reference in New Issue
Block a user