5
5
import json
6
6
from warnings import warn
7
7
from typing import Dict , List
8
+ from datetime import datetime
8
9
9
10
import re
10
11
import requests
36
37
EVALUATE_SMARTCLASS ,
37
38
GET_SMARTCLASS_DETAILS ,
38
39
LIST_RULE_INSTANCES ,
39
- J1QL_FROM_NATURAL_LANGUAGE
40
+ J1QL_FROM_NATURAL_LANGUAGE , UPDATE_RELATIONSHIP
40
41
)
41
42
42
43
@@ -63,9 +64,7 @@ class JupiterOneClient:
63
64
def __init__ (self , account : str = None , token : str = None , url : str = DEFAULT_URL , sync_url : str = SYNC_API_URL ):
64
65
self .account = account
65
66
self .token = token
66
- self .url = url
67
- self .query_endpoint = self .url
68
- self .rules_endpoint = self .url + "/rules/graphql"
67
+ self .graphql_url = url
69
68
self .sync_url = sync_url
70
69
self .headers = {
71
70
"Authorization" : "Bearer {}" .format (self .token ),
@@ -115,7 +114,7 @@ def _execute_query(self, query: str, variables: Dict = None) -> Dict:
115
114
s .mount ('https://' , HTTPAdapter (max_retries = retries ))
116
115
117
116
response = s .post (
118
- self .query_endpoint , headers = self .headers , json = data , timeout = 60
117
+ self .graphql_url , headers = self .headers , json = data , timeout = 60
119
118
)
120
119
121
120
# It is still unclear if all responses will have a status
@@ -401,6 +400,28 @@ def create_relationship(self, **kwargs) -> Dict:
401
400
response = self ._execute_query (query = CREATE_RELATIONSHIP , variables = variables )
402
401
return response ["data" ]["createRelationship" ]
403
402
403
+ def update_relationship (self , ** kwargs ) -> Dict :
404
+ """
405
+ Update a relationship (edge) between two entities (vertices).
406
+
407
+ args:
408
+ relationship_id (str): Unique _id of the relationship
409
+ properties (dict): Dictionary of key/value relationship properties
410
+ """
411
+ now_dt = datetime .now ()
412
+
413
+ variables = {
414
+ "relationshipId" : kwargs .pop ("relationship_id" ),
415
+ "timestamp" : datetime .strptime (str (now_dt ), "%Y-%m-%d %H:%M:%S.%f" ).timestamp ()
416
+ }
417
+
418
+ properties = kwargs .pop ("properties" , None )
419
+ if properties :
420
+ variables ["properties" ] = properties
421
+
422
+ response = self ._execute_query (query = UPDATE_RELATIONSHIP , variables = variables )
423
+ return response ["data" ]["updateRelationship" ]
424
+
404
425
def delete_relationship (self , relationship_id : str = None ):
405
426
"""Deletes a relationship between two entities.
406
427
@@ -542,6 +563,23 @@ def upload_combined_batch_json(self, instance_job_id: str = None, combined_paylo
542
563
543
564
return response
544
565
566
+ def bulk_delete_entities (self , instance_job_id : str = None , entities_list : list = None ):
567
+ """Send a request to bulk delete existing entities.
568
+
569
+ args:
570
+ instance_job_id (str): The "Job ID" for the Custom Integration job.
571
+ entities_list (list): List of dictionaries containing entities _id's to be deleted.
572
+ """
573
+ endpoint = f"/persister/synchronization/jobs/{ instance_job_id } /upload"
574
+
575
+ data = {
576
+ "deleteEntities" : entities_list
577
+ }
578
+
579
+ response = self ._execute_syncapi_request (endpoint = endpoint , payload = data )
580
+
581
+ return response
582
+
545
583
def finalize_sync_job (self , instance_job_id : str = None ):
546
584
"""Start a synchronization job.
547
585
0 commit comments