Skip to content

Commit

Permalink
Action Builder Remove Tag Method (#890)
Browse files Browse the repository at this point in the history
* include remove_tagging method

* complete logic for error catching

* test remove_tag method

* build endpoint based on tag ID

* correct comparison in test

* lint remove tag method

* lint testing file

---------

Co-authored-by: sharinetmc <[email protected]>
  • Loading branch information
ydamit and sharinetmc authored Sep 14, 2023
1 parent 0b9db94 commit a25943b
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
81 changes: 81 additions & 0 deletions parsons/action_builder/action_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,87 @@ def add_section_field_values_to_record(
identifier=identifier, data=data, campaign=campaign
)

def remove_tagging(
self,
identifier=None,
tag_id=None,
tag_name=None,
tagging_id=None,
campaign=None,
):
"""
Remove one or more tags (i.e. custom field value) from an existing entity or connection
record in Action Builder. The basis for this end point is the combination of the tag's
interact ID and that of the specific tagging. The tag ID can usually be determined from
the tag's name, and the tagging ID can be derived if the identifier of the entity or
connection record is supplied instead.
`Args:`
identifier: str
Optional. The unique identifier for an entity or connection record being updated.
If omitted, `tagging_id` must be provided.
tag_id: str
Optional. The unique identifier for the tag being removed. If omitted, `tag_name`
must be provided.
tag_name: str
Optional. The exact name of the tag being removed. May result in an error if
multiple tags (in different fields/sections) have the same name. If omitted,
`tag_id` must be provided.
tagging_id: str
Optional. The unique identifier for the specific application of the tag to an
individual entity or connection record. If omitted, `identifier` must be provided.
campaign: str
Optional. The 36-character "interact ID" of the campaign whose data is to be
retrieved or edited. Not necessary if supplied when instantiating the class.
`Returns:`
API response JSON which contains `{'message': 'Tag has been removed from Taggable
Logbook'}` if successful.
"""

if {tag_name, tag_id} == {None}:
raise ValueError("Please supply a tag_name or tag_id!")

if {identifier, tagging_id} == {None}:
raise ValueError(
"Please supply an entity or connection identifier, or a tagging id!"
)

campaign = self._campaign_check(campaign)
endpoint = "tags/{}/taggings"

if tag_name and {tag_id, tagging_id} == {None}:
tag_data = self.get_tag_by_name(tag_name, campaign=campaign)
tag_count = tag_data.num_rows

if tag_count > 1:
error_msg = f"Found {tag_count} tags with this name. "
error_msg += "Try with using the unique interact ID"
raise ValueError(error_msg)

tag_id = tag_data["identifiers"][0][0].split(":")[1]
logger.info(f"Tag {tag_name} has ID {tag_id}")

if tagging_id and not tag_id:
raise ValueError("Cannot search based on tagging ID alone.")

if tag_id and not tagging_id:
taggings = self._get_all_records(self.campaign, endpoint.format(tag_id))
taggings_filtered = taggings.select_rows(
lambda row: identifier
in row["_links"]["action_builder:connection"]["href"]
if row["item_type"] == "connection"
else identifier in row["osdi:person"]["href"]
)
tagging_id = [
x.split(":")[1]
for x in taggings_filtered["identifiers"][0]
if "action_builder" in x
][0]

logger.info(f"Removing tag {tag_id} from {identifier or tagging_id}")
return self.api.delete_request(
f"campaigns/{campaign}/{endpoint.format(tag_id)}/{tagging_id}"
)

def upsert_connection(self, identifiers, tag_data=None, campaign=None):
"""
Load or update a connection record in Action Builder between two existing entity records.
Expand Down
17 changes: 17 additions & 0 deletions test/test_action_builder/test_action_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ def setUp(self, m):
f"action_builder:{self.fake_entity_id}"
]

self.fake_tag_id = "fake_tag_id"
self.fake_tagging_id = "fake_tagging_id"
self.fake_remove_tag_resp = {
"message": "Tag has been removed from Taggable Logbook"
}

self.fake_connection = {"person_id": "fake-entity-id-2"}

@requests_mock.Mocker()
Expand Down Expand Up @@ -362,6 +368,17 @@ def test_add_section_field_values_to_record(self, m):
)
self.assertEqual(add_tags_response, self.fake_tagging)

@requests_mock.Mocker()
def test_remove_tagging(self, m):
m.delete(
f"{self.api_url}/tags/{self.fake_tag_id}/taggings/{self.fake_tagging_id}",
json=self.fake_remove_tag_resp,
)
remove_tag_resp = self.bldr.remove_tagging(
tag_id=self.fake_tag_id, tagging_id=self.fake_tagging_id
)
self.assertEqual(remove_tag_resp, self.fake_remove_tag_resp)

def connect_callback(self, request, context):
# Internal method for returning constructed connection data to test

Expand Down

0 comments on commit a25943b

Please sign in to comment.