Copy // moovIT GmbH
// Distribute search filters from a blueprint user to a dedicated user
// B Dimmel
// Version 2.1
// Date June 2nd 2025
// === Configuration ===
var baseUrl = "{stream.variable.hostAddress}";
var authHeader = "{stream.variable.bearerToken}";
var blueprintUser = "{stream.variable.blueprintUser}"; // e.g. "admin"
var dedicatedUser = "{stream.variable.destinationUser}"; // e.g. "ben"
// === Endpoints ===
var listEndpoint = "/v1/members/searchFilter";
var postEndpoint = "/v1/members/searchFilter";
// === Utilities ===
function asResponse(con) {
var code = con.getResponseCode();
// If status >= 400, read from getErrorStream(), else from getInputStream()
var stream = (code >= 400 ? con.getErrorStream() : con.getInputStream());
var inr = new java.io.BufferedReader(
new java.io.InputStreamReader(stream, "UTF-8")
);
var line;
var sb = new java.lang.StringBuffer();
while ((line = inr.readLine()) !== null) {
sb.append(line);
}
inr.close();
return { status: code, data: sb.toString() };
}
function httpGet(path) {
var url = new java.net.URL(baseUrl + path);
var con = url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Authorization", authHeader);
con.setRequestProperty("Accept", "application/json");
return asResponse(con);
}
function httpPost(path, body) {
var url = new java.net.URL(baseUrl + path);
var con = url.openConnection();
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Authorization", authHeader);
con.setRequestProperty("Content-Type", "application/json");
var wr = new java.io.OutputStreamWriter(con.getOutputStream(), "UTF-8");
wr.write(JSON.stringify(body));
wr.close();
return asResponse(con);
}
function httpDelete(path) {
var url = new java.net.URL(baseUrl + path);
var con = url.openConnection();
con.setRequestMethod("DELETE");
con.setRequestProperty("Authorization", authHeader);
return asResponse(con);
}
// Compare two filter‐objects to see if their “criteria” match exactly.
// We check: 1) filter-array deep equality, 2) type, 3) any, 4) sortParameter.
function isSameCriteria(existingObj, incomingObj) {
var f1 = JSON.stringify(existingObj.filter);
var f2 = JSON.stringify(incomingObj.filter);
var sameFilterArray = (f1 === f2);
var sameType = (existingObj.type === incomingObj.type);
var sameAny = (existingObj.any === incomingObj.any);
var sp1 = (existingObj.sortParameter === null ? "null" : String(existingObj.sortParameter));
var sp2 = (incomingObj.sortParameter === null ? "null" : String(incomingObj.sortParameter));
var sameSortParam = (sp1 === sp2);
return sameFilterArray && sameType && sameAny && sameSortParam;
}
// === Main Logic ===
var respAll = httpGet(listEndpoint);
var output = {};
if (respAll.status === 401) {
// Unauthorized: token is invalid or expired
output = {
message: "Unauthorized (HTTP 401) – check your authHeader token",
httpStatus: 401,
raw: respAll.data
};
} else if (respAll.status !== 200) {
// Any other failure fetching master list
output = {
message: "Failed to retrieve filters",
httpStatus: respAll.status,
raw: respAll.data
};
} else {
// respAll.status === 200 → continue
var allFilters = JSON.parse(respAll.data);
// 1) Extract only blueprintUser’s filters
var blueprintFilters = allFilters.filter(function(f) {
return f.username === blueprintUser;
});
if (blueprintFilters.length === 0) {
output = {
message: "No filters found for user \"" + blueprintUser + "\""
};
} else {
// 2) Extract existing dedicatedUser’s filters, build a map by name
var existingDedicated = allFilters.filter(function(f) {
return f.username === dedicatedUser;
});
var existingMap = {};
existingDedicated.forEach(function(f) {
existingMap[f.name] = f;
});
// 3) Loop over blueprintFilters: skip / DELETE+POST (update) / POST (create)
var results = [];
blueprintFilters.forEach(function(f) {
var nameKey = f.name;
var existing = existingMap[nameKey];
var incomingCriteria = f.filter;
var incomingType = f.type;
if (existing) {
// Case A: same‐name filter already exists on dedicatedUser
if (isSameCriteria(existing, f)) {
// A1: Criteria are identical → SKIP (409)
results.push({
name: nameKey,
type: existing.type,
httpStatus: 409,
change: "none",
criteria: incomingCriteria,
response: "Skipped: already exists with identical criteria for \"" + dedicatedUser + "\""
});
} else {
// A2: Exists under same name but different criteria → DELETE then POST
var deletePath = listEndpoint + "/" + existing.id;
var delResp = httpDelete(deletePath);
if (delResp.status === 200 || delResp.status === 204) {
// Now re-POST with updated criteria & updated type
delete f.id;
f.username = dedicatedUser;
var postResp = httpPost(postEndpoint, f);
// If POST returns 400 (duplicate), treat as skipped
if (postResp.status === 400) {
results.push({
name: nameKey,
type: incomingType,
httpStatus: 409,
change: "none",
criteria: incomingCriteria,
response: "Skipped (duplicate) after delete took effect for \"" + dedicatedUser + "\""
});
} else {
results.push({
name: nameKey,
type: incomingType,
httpStatus: postResp.status,
change: "updated",
criteria: incomingCriteria,
response: "Deleted old (ID=" + existing.id + "), then created new: " + postResp.data
});
}
} else {
// DELETE failed—report and skip POST
results.push({
name: nameKey,
type: existing.type,
httpStatus: delResp.status,
change: "none",
criteria: incomingCriteria,
response: "Failed to delete existing filter (ID=" + existing.id + "): " + delResp.data
});
}
}
} else {
// Case B: No existing filter under this name → POST directly
delete f.id;
f.username = dedicatedUser;
var postResp = httpPost(postEndpoint, f);
if (postResp.status === 400) {
// Duplicate (somehow); treat as skipped
results.push({
name: nameKey,
type: incomingType,
httpStatus: 409,
change: "none",
criteria: incomingCriteria,
response: "Skipped: duplicate filter for \"" + dedicatedUser + "\""
});
} else {
results.push({
name: nameKey,
type: incomingType,
httpStatus: postResp.status,
change: "created",
criteria: incomingCriteria,
response: postResp.data
});
}
}
});
output = { results: results };
}
}
// Print JSON to stdout (Nashorn will echo this)
JSON.stringify(output, null, 2);