Sailpoint Identity IQ generates an error: sailpoint.connector.ConnectorException: Build Rule must return a Map - sailpoint

I want to display only the identities whose type is either "interne" or "externe".
Here is my code in Sailpoint:
import sailpoint.connector.DelimitedFileConnector;
Map map = DelimitedFileConnector.defaultBuildMap(cols, record);
String Type = (String) map.get( "TYPE" );
if(!Type.contains("Interne") && !Type.contains("Externe")){
return null;
}
return map;
When i launch an aggregation account task, i have the error:
Exception lors du regroupement. Cause : java.lang.RuntimeException: sailpoint.connector.ConnectorException: Build Rule must return a Map.

The issue is you are directly calling the DelimitedFileConnector.defaultBuildMap(cols, record); which may return, so inturn you are not returning a empty hashmap, but a null value.
So i would change the following.
return null!=map ? map:new HashMap();
This way you are checking for map is null or not and return correct value.

Related

How to use condition and multiple steps in a reactive function

I'm currently building a reactive app using kotlin quarkus and mutiny, being new to reactive programming i wonder what's the best way to handle the following workflow :
try to find an item in the database (dynamodb)
if it exists return a value indicating this to the caller
if it does not exists call the save service
call an external service to get some data
update the item in database with those data from the external service
return a value indicating that the object has been created
Here's my code for now :
fun createCard(creationOrder: CreationOrder): Uni<CardCreationResult> {
return creationOrdersRepository.findByOrderId(creationOrder.orderId)
.onItem().transform {item ->
if (item != null) {
CardCreationResult.AlreadyCreated
} else {
creationOrdersRepository.save(creationOrder)
//TODO external webservice call
val cardNumber = UUID.randomUUID().toString()
creationOrdersRepository.updateCardNumberAndStatus(externalServiceCallResult)
CardCreationResult.Created
}
}
}
This method will eventually be called by a rest endpoint.
creationOrdersRepository.save and creationOrdersRepository.updateCardNumberAndStatus returns a CompletableFuture (i'm using the quarkus amazon dynamodb client).
Is this the right way to do it ? Should i wrap the save and updateCardNumberAndStatus results in Uni (i have been trying to but keep getting type error) ?
I don't believe your code does what you expect. If I understand correctly you need to "save" and "update" before emitting your result. So, you need something like (in Java, as my Kotlin is not great):
return creationOrdersRepository.findByOrderId(creationOrder.orderId)
// We will be returning a Uni as the save, update and the web service are
// async
.onItem().transformToUni(item -> {
if (item != null) {
return Uni.createFrom().item(CardCreationResult.AlreadyCreated);
} else {
// Create an Uni from the save operation
Uni<Void> save = Uni.createFrom().completionStage(() ->
creationOrdersRepository.save(creationOrder));
// This uni represents the invocation of the remote service
Uni<String> webService = callWebService();
// we chain the operations save -> web service -> update -> Created
return save
.chain(webService)
.chain(externalServiceCallResult ->
Uni.createFrom().completionStage(() -> creationOrdersRepository
.updateCardNumberAndStatus(externalServiceCallResult)
)
.replaceWith(CardCreationResult.Created);
}

firestore security: exist and get within the same function does not work

I'm trying to get() a document and then based on the result, to see if another document exists using exists(). However, this fails because the variable that should be storing a string remains an object, namely parentId below.
Observed
It does not convert parentId to a string and it fails when calling exists().
function validateAuth() {
let parentId = get(/databases/$(database)/documents/items/$(resource.data.itemId)).data.parentId
return exists(/databases/$(database)/documents/other-items/$(parentId):$(request.auth.uid))
}
Expected
It should convert parentId to a string so that exists can be performed.
What I've tried
This below works, and the function is able to evaluate when the document ID using parentId exists and doesn't exist.
function validateAuth() {
// let parentId = get(/databases/$(database)/documents/items/$(resource.data.itemId)).data.parentId
let parentId = 'some-id';
return exists(/databases/$(database)/documents/other-items/$(parentId):$(request.auth.uid))
}
Now, I removed the string concatenation below but this still throws an error
function validateAuth() {
// let parentId = get(/databases/$(database)/documents/items/$(resource.data.itemId)).data.parentId
let parentId = 'some-id';
return exists(/databases/$(database)/documents/other-items/$(parentId))
}
The below does not work, and the parentId is still an object when ran in the simulator.
function validateAuth() {
let parentId = get(/databases/$(database)/documents/items/$(resource.data.itemId)).data.parentId;
let parentIdStr = string(parentId);
return exists(/databases/$(database)/documents/other-items/$(parentIdStr):$(request.auth.uid))
}
Error details
I get this error after the console processes it for about 5 ~ 10 seconds, which is a lot longer than if the requests are processed correctly.
Error: Invalid argument provided to call. Function: [exists], Argument: ["||invalid_argument||"]
I couldn't find any documentation about this. Does anyone know if this should work or if there are workarounds?
The part with colon seems to be the problem:
$(parentIdStr):$(request.auth.uid)
Try refactoring that to a single element in path:
$(parentIdStr+':'+request.auth.uid)

Repository in PRE_WRITE event returns query data, not saved data

During a PUT call to an item I need to get the current saved values in order to compare them to request params.
Say the PUT call contains a name parameter that is different from the currently saved one.
I thought getting the entity with $repository->findOneBy would return the saved value but it's not, I'm getting the PUT param value instead.
The setup is taken from https://api-platform.com/docs/core/events :
const ALLOWED_METHOD = Request::METHOD_PUT;
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => [
['preWriteWorkflow', EventPriorities::PRE_WRITE],
],
];
}
public function preWriteWorkflow(GetResponseForControllerResultEvent $event)
{
$entity = $event->getControllerResult();
if (!($entity instanceof MyEntity)) {
return;
}
$route = "/{$entity->getId()}";
$result = $this->checkRequestFromControllerResult($event, $route);
if (!$result) {
return;
}
// Getting entity from repository in order to get the currently saved value
$savedEntity = $this->MyEntityRepository->findOneBy(['id' => $entity->getId()]);
// Both will return the Name value of the PUT call
// Shouldn't $savedEntity return the currently saved name ?
$entity->getName();
$savedEntity->getName();
}
What is the reason behind this behavior? Is there a way to get eventArgs injected in this method so that I can use getEntityChangeSet or hasChangedField?
What is the reason behind this behavior?
This is doctrine behaviour. Once you've fetched an entity, the instance is stored and always returned. Given that, you have one and only one instance of your entity during request's lifecycle.
$event->getControllerResult() === $repository->findBy($id); //true !
Roughly, Api-platform calls Doctrine and fetch your entity while executing the ReadListener. Because this is an object, doctrine's find*() methods always returns a pointer/reference to the entity, even if it is updated.
Yes, during a PUT request, the updated instance is the fetched one, in order to trigger doctrine update actions at the end of the request.
An easy way to keep an instance of the so called previous object is to clone it before the Deserialization event.
Note that this strategy is used by api-platform with the security_post_denormalize and previous_object security attributes.
EDIT
Working on a similar use case, i've found that the ReadListener stores the current object within the Request under the "data" key, whereas the previous object is stored within the "previous_data" key.
$entity = $request->get('data');
$previousEntity = $request->get('previous_data'); // This is a clone.

Why Flow still complains about null values for document.getElementById

Why even with an IF check, Flow still complains about a possibly null value
if(document && document.getElementById("myID") && document.getElementById("myID").offsetWidth){
console.log(document.getElementById("myID").offsetWidth);
}
Gives this error
^ property `offsetWidth`. Property cannot be accessed on possibly null value
Flow has no way to know that the success of first call to getElementById means that the later ones will also succeed. For all it knows, reading the offsetWidth property could cause getElementById to start returning null the next time it is called.
You'll need to store the value, e.g.
const myIdEl = document && document.getElementById("myID");
if(myIdEl && myIdEl.offsetWidth) {
console.log(myIdEl.offsetWidth);
}
this way there is no way for myIdEl to become null after it has been referenced.
For HTMLElement (and extensions of HTMLElement like VideoHTMLElement) in FlowType, I'd recommend using instanceof to validate the Type and to validate that it's not null.
Also, I don't believe you need to check if document exists, that is defined globally in flow (1)*
<HTMLElement> Example
const myIdEl: ?HTMLElement = document.getElementById('myID');
if (myIdEl instanceof HTMLElement) {
// continue
console.log(myIdEl.offsetWidth);
}
<HTMLSelectElement> Example
const selectEl: ?HTMLElement = document.getElementById('someSelectElement');
// Checks correct type (!null !undefined come for free)
if (selectEl instanceof HTMLSelectElement) {
const selectedVal = selectEl.options[selectEl.selectedIndex].value;
}
<HTMLVideoElement> Example using invariant
import invariant from 'invariant';
const videoContent = document.getElementById('video-player');
invariant(videoContent instanceof HTMLVideoElement, 'No video element');
// do stuff with video api
videoContent.volume = 0;
videoContent.plause();
https://github.com/facebook/flow/blob/f3f29f7fd8c5aa73ac5a8a546ccfbc29cd7505fe/lib/dom.js#L1288

Exception in template helper: Error: Match error

I'm trying to perform a custom sort using a comparator function from within a template helper in Meteor.
Here is my template helper:
Template.move_list.helpers({
assets() {
return Assets.find({}, { sort: sortFunction });
}
});
And here is the comparator function:
const sortFunction = function (doc1, doc2) {
const barcodes = Session.get('barcodesArray');
if (barcodes.indexOf(doc1.barcode) === -1 || barcodes.indexOf(doc2.barcode) === -1) {
return 0;
}
let last = null;
_.each(barcodes, function (barcode) {
if (barcode === doc1.barcode) last = doc1.barcode;
if (barcode === doc2.barcode) last = doc2.barcode;
});
return last === doc1.barcode ? 1 : -1;
}
Error
When the page loads, the following error is returned:
Exception in template helper: Error: Match error: Failed Match.OneOf, Match.Maybe or Match.Optional validation
I put a breakpoint in chrome into the sortFunction, however the function was never entered and the breakpoint never reached.
Of course, the error is not throw when I remove sort.
References
This feature is not very well documented, however here is the relevant part of the docs:
For local collections you can pass a comparator function which receives two document objects, and returns -1 if the first document comes first in order, 1 if the second document comes first, or 0 if neither document comes before the other. This is a Minimongo extension to MongoDB.
And the commit by mitar adding the functionality, with example code from the test:
var sortFunction = function (doc1, doc2) {
return doc2.a - doc1.a;
};
c.find({}, {sort: sortFunction})
Can anyone make sense of this error?
Edit:
This issue should be resolved in Meteor >= v1.3.3.1.
Local collections (i.e, client-side and in-memory server-side collections) will allow to pass a function as the sort clause.
The error comes from the mongo package, where the spec does not allow sort to be a function.
#mitar changed LocalCollection in the minimongo package. LocalCollection is part of the Mongo.Collection object on the client (its _collection attribute), but queries are still checked according to the original mongo spec. I believe this to be a bug, as the spec was not updated to reflect the change.
To overcome this (in the meantime), either have the function accept a sub-field, such that the sort value is an object:
var sortFunction = function (x, y) {
return x - y;
};
c.find({}, {sort: {a: sortFunction}});
or use the c._collection.find() instead, which will work (as far as I can tell), except it will not apply any transformations defined for the collection.
var sortFunction = function (doc1, doc2) {
return doc2.a - doc1.a;
};
c._collection.find({}, {sort: sortFunction});

Resources