Neo4j throwing Neo.ClientError.Transaction.TransactionHookFailed when Cypher is executed - database

Please can you please point what's wrong with this cypher statement because when the statement is executed, the database is throwing TransactionHookFailed error. Also, it might help if you can explain the meaning of this error.
MATCH (user:User { id: $userId })
MATCH (event:Event { id: $eventId })-[:BOUND_TO_EXPIRE]->(expiryDate)
WITH user, event, apoc.nodes.connected(user, event, 'ORGANIZED>') AS isOrganizer, expiryDate
// Make sure the user is the organizer of the event
WHERE isOrganizer = true
// Just delete event
DETACH DELETE expiryDate
DETACH DELETE event
// Remove event from the user's event
SET user.noOfEvents = user.noOfEvents - 1
RETURN {
clientResponse: true
}

I had this error
Neo.ClientError.Transaction.TransactionHookFailed
because a constraint on the database required certain fields to be set when updating a node. I was setting other fields but not the required ones.
Perhaps your database has constraints on it as well.
You would get a syntax error if the cypher code was bad, so that's probably not the case.

Related

Creating a Multi-Contact Event with Apex in Salesforce

I am attempting to use Apex to create a multi-contact event.
I have already enabled Allow Users to Relate Multiple Contacts to Tasks and Events in the activity settings in the scratch org.
I am following the guide and the example at the bottom of these docs but I am constantly getting an error when pushing to the scratch org:
// ...
event.setEventWhoIds(attendeeContactIds);
// ...
Method does not exist or incorrect signature: void setEventWhoIds(List<String>) from the type Event.
I also tried to write directly to the field with:
event.EventWhoIds = attendeeContactIds;
With that, I get the error, that the field is not writable.
attendeeContactIds is a List of Strings representing Contact IDs.
What could I be missing? 🤔🙇🏻‍♂️
It's bit stupid, it's readonly in apex. It's exposed so integrations can quickly create event and essentially a related list together in one all-or-nothing transaction. See also https://salesforce.stackexchange.com/questions/238094/eventwhoids-is-not-writeable-in-apex-class-but-working-on-jsforce
Try something like that?
Savepoint sp = Database.setSavepoint();
event e = new Event(
StartDateTime = System.now(),
EndDateTime = System.now().addHours(1)
);
insert e;
List<EventRelation> invitations = new List<EventRelation>();
for(Contact c : [SELECT Id FROM Contact LIMIT 5]){
invitations.add(new EventRelation(
EventId = e.Id,
RelationId = c.Id,
IsInvitee = true
));
}
insert invitations;
Database.rollback(sp); // unless you really want to send it out

How to ensure unique key while using Parse database

I need unique records my Parse object but due to the 'saveinbackground' a simple find() on the client didn't do the job. Even adding and setting a boolean like bSavingInbackGround and skip an additional save if true wouldn't prevent my app from creating duplicates.
Ensure unique keys is obvious very helpfull in many (multi user) situations.
Parse CloudCode would be the right way but I didn't find a proper solution.
After doing some trail and error testing I finally got it to work using Cloud Code. Hope it helps someone else.
My 'table' is myObjectClass and the field that needs to be unique is 'myKey'.
Add this to main.js an upload to Parse Server Cloud Code.
Change myObjectClass and 'myKey' to suit your needs:
Parse.Cloud.beforeSave("myObjectClass", function(request, response) {
var myObject = request.object;
if (myObject.isNew()){ // only check new records, else its a update
var query = new Parse.Query("myObjectClass");
query.equalTo("MyKey",myObject.get("myKey"));
query.count({
success:function(number){ //record found, don't save
//sResult = number;
if (number > 0 ){
response.error("Record already exists");
} else {
response.success();
}
},
error:function(error){ // no record found -> save
response.success();
}
})
} else {
response.success();
}
});
Your approach is the correct approach, but from a performance point of view, I think using query.first() is faster than query.count() since query.first() will stop as soon as it finds a matching record, whereas query.count() will have to go through the whole class records to return matching the number of matching records, this can be costly if you have a huge class.

CakePHP3: Check if model exists

I have a search engine which calls a Cakephp action and receives which model the engine should search in eg. "Projects". The variable is called $data_type;
Right now I use this to check if the model exists:
// Check if Table really exists
if(!TableRegistry::get($data_type)){
// Send error response to view
$response = [
'success' => false,
'error' => 'Data type does not exist'
];
$this->set('response', $response);
return;
}
I'm not sure I'm doing it the right or the safest way to check if a model exists, because I don't know if the TableRegistry::get() function is vulnerable to SQL injection behind the scenes.
I also found that inputing an empty string to the get() function doesn't need in a false result??? Is there a safe solution I can implement that will solve my problem?
TableRegistry::get() is not safe to use with user input
First things first. It's probably rather complicated to inject dangerous SQL via TableRegistry::get(), but not impossible, as the alias passed in the first argument will be used as the database table name in case an auto/generic-table instance is created. However the schema lookup will most likely fail before anything else, also the name will be subject to inflection, specifically underscore and lowercase inflection, so an injection attempt like
Foo; DELETE * FROM Bar;
would end up as:
foo;d_e_l_e_t_e*f_r_o_m_bar;
This would break things as it's invalid SQL, but it won't cause further harm. The bottom line however is that TableRegistry::get() cannot be regarded as safe to use with user input!
The class of the returned instance indicates a table class' existence
TableRegistry::get() looks up and instantiates possible existing table classes for the given alias, and if that fails, it will create a so called auto/generic-table, which is an instance of \Cake\ORM\Table instead of an instance of a concrete subclass thereof.
So you could check the return value against \Cake\ORM\Table to figure whether you've retrieved an instance of an actual existing table class:
$table = TableRegistry::get($data_type);
if (get_class($table) === \Cake\ORM\Table::class) {
// not an existing table class
// ...
}
Use a whitelist
That being said, unless you're working on some kind of administration tool that explicitly needs to be able to access to all tables, the proper thing do would be to use some sort of whitelisting, as having users arbitrarily look up any tables they want could be a security risk:
$whitelist = [
'Projects',
'...'
];
if (in_array($data_type, $whitelist, true) !== true) {
// not in the whitelist, access prohibited
// ...
}
Ideally you'd go even further and apply similar restrictions to the columns that can be looked up.
You may want to checkout https://github.com/FriendsOfCake/awesome-cakephp#search for some ready made search plugins.

Apex trigger which provides targets on sub campaign generates the error on parent campaign

I have a problem with one trigger. I was trying to set up the solution which will give me the possibility to assign flexible targets for campaigns. I was trying to solve it via formula field but it occurred to be too complex and I was advised it needs to be the apex trigger. I created the custom setting of list type, so then I could query it in the apex trigger. I created the "Apex_Calculator__c" field which combined values from two fields (Event Region [located on the parent campaign level] and Started Campaign [located on the sub-campaign level]). The value from the "Apex_Calculator__c" field was about to bring the same values as in the custom setting.
My knowledge of Apex triggers is limited, so I asked for the help on the internet. I received the help and the trigger was bringing target values in the sub campaign. However, the problem occurred on the parent campaign level. As far as I wanted to change the Event Region (which as I mentioned is part of the "Apex_Calculator__c" formula field), I started to receive the error message:
*
PopulateTarget: execution of BeforeUpdate caused by:
System.NullPointerException: Attempt to de-reference a null object:
Trigger.PopulateTarget: line 18, column 1
*
trigger PopulateTarget on Campaign (before insert, before update)
{
Map <String, Id> recordTypes = new Map <String, Id> ();
for (RecordType recordType : [SELECT Id, DeveloperName FROM RecordType WHERE sObjectType = 'Campaign'])
{
if (recordType.DeveloperName == 'Conference')
{
recordTypes.put(recordType.DeveloperName, recordType.Id);
}
}
for(Campaign campaign : Trigger.new)
{
// Make sure that the campaign record type is not in the map (in the map we keep the ones that we want to exclude)
if (recordTypes.get(campaign.RecordTypeId) == null && String.isNotBlank(campaign.Apex_Calculator__c) == true)
{
String target = DSTargets__c.getInstance(campaign.Apex_Calculator__c).Target__c;
campaign.DS_Target_Multiplier__c = Target;
}
}
}
I feel really lost what is wrong in here. Could anyone help me with this error?
Looks like you don't have DSTargets custom settings for some campaign.Apex_Calculator__c values.
Try this:
// Make sure that the campaign record type is not in the map (in the map we keep the ones that we want to exclude)
if (recordTypes.get(campaign.RecordTypeId) == null && String.isNotBlank(campaign.Apex_Calculator__c) == true)
{
if (DSTargets__c.getInstance(campaign.Apex_Calculator__c) == null)
{
System.debug('### A DSTargets named \'' + campaign.Apex_Calculator__c + '\' doesn't exist');
continue;
}
String target = DSTargets__c.getInstance(campaign.Apex_Calculator__c).Target__c;
campaign.DS_Target_Multiplier__c = Target;
}

Illegal polymorphic assignment from polymorphic domain [SOBJECT:User, SOBJECT:Calendar]

I am writing a task's trigger and getting an error in salesforce Illegal polymorphic assignment from polymorphic domain [SOBJECT:User, SOBJECT:Calendar]
trigger Status_Change on Task (after update) {
List<Task>updated_tasks=trigger.new;
List<Task> tt=trigger.old;
Task_History__c history=new Task_History__c();
Integer i=0;
for(i=0;i<updated_tasks.size();i++)
{
history.Name=tt.get(i).Subject;
history=new Task_History__c();
history.OldValue__c=tt.get(i).Status;
history.NewValue__c=updated_tasks.get(i).Status;
history.User__c=updated_tasks.get(i).Owner;
insert history;
}
}
error is on line
history.User__c=updated_tasks.get(i).Owner;
When I write history.User__c=updated_tasks.get(i).owner.id then there is no error
but when I tried to get a User's email address from this id then its showing no user corresponding to this id. How do I get Owner's user id from Task SObject's owner field. I think error is due to Owner is a lookup to [SObject.User,SObject.Calender].so owner's id should be different from User'id .but how to get only User's id from Owner's field in Task object?
You are so close. The syntax is:
history.User__c=updated_tasks.get(i).OwnerId;
You were correct. the task.Owner field is an SObject, task.Owner.Id is valid, but the value being referenced is not populated in the trigger context.
Your trigger is not very well written, it has a dml statement in a loop, and there doesn't appear to be a lookup from the task history to the task, I have referenced one in the updated example below.
trigger Status_Change on Task (after update) {
List<Task_History__c> histories = new List<Task_History__c>();
Task oldValue;
for(Task task : Trigger.new) {
oldValue = Trigger.oldMap.get(task.Id);
histories.add(new Task_History__c(
Name=task.Subject,
OldValue__c=oldValue.Status,
NewValue__c=task.Status,
User__c=task.OwnerId,
//This should be created as well
Task__c=task.Id
));
}
if(histories.size() > 0) {
insert histories;
}
}

Resources