Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UID2-2760 Add IdentityMapClient #39

Merged
merged 9 commits into from
May 22, 2024

Conversation

caroline-ttd
Copy link
Contributor

@caroline-ttd caroline-ttd commented May 11, 2024

  1. Added IdentityMapClient
  2. Sample IdentityMapClient tests
  3. IdentityMapClient Integration tests
  4. Fixed make docker and remove broken commands in readme

@caroline-ttd caroline-ttd changed the title Add IdentityMapClient UID2-2760 Add IdentityMapClient May 11, 2024
examples/sample_identity_map_client.py Outdated Show resolved Hide resolved


class IdentityMapClient:
"""Client for interacting with UID2 Identity Map services
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that this class needs to work for EUID as well. Instead of UID2 in this file we can say UID2 and EUID or UID

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated it to UID

@caroline-ttd caroline-ttd marked this pull request as ready for review May 15, 2024 22:25
"email_hash": self.hashed_normalized_emails,
"phone_hash": self.hashed_normalized_phones
}
return json.dumps({k: v for k, v in json_object.items() if v is not None})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize the variables hashed_normalized_emails and hashed_normalized_phones as None, and then set their values later. This approach allows us to create objects like {"email_hash":[]} instead of {} when the input is empty. Passing {} to the operator would result in a 400 bad request error.

@caroline-ttd caroline-ttd requested review from asloobq and jon8787 May 16, 2024 22:02
if identity_type == IdentityType.Email:
self.hashed_normalized_emails = []
for email in emails_or_phones:
if already_hashed:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably don't need to enter the for loop if already_hashed is true . You can set self.hashed_normalized_emails.append( emails_or_phones)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I change it to self.hashed_normalized_emails = emails_or_phones

self.hashed_normalized_emails.append( emails_or_phones) will add emails_or_phones as one element in the hashed_normalized_emails list.

@@ -0,0 +1,63 @@
import json

from uid2_client import IdentityType, normalize_email_string, get_base64_encoded_hash, is_phone_number_normalized, \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some imports appear unused

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thank you. I may copy paste from other class....

# which contains raw uid or the reason why it is unmapped

def _usage():
print('Usage: python3 sample_sharing_client.py <base_url> <api_key> <client_secret> <email_1> <email_2> ... <email_n>'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sample_identity_map_client.py instead of sample_sharing_client.py

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, good catch!

from uid2_client import IdentityMapClient, IdentityMapInput


# this sample client takes email addresses or phone numbers as input and generates an IdentityMapResponse object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this example demonstrates mapping emails only, so either we should mention only emails here or mention all 4 types including hashes of emails and phones

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I updated the description

if not self.is_success():
raise ValueError("Got unexpected identity map status: " + self.status)

body = self._get_body_as_json(response_json)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicking here: I don't see much value in refactoring this into a separate method since its not called from anywhere else and its just one line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree, I removed that method.


class MappedIdentity:
def __init__(self, raw_uid, bucket_id):
self.raw_uid = raw_uid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to denote that properties should not be accessed directly it is a convention to start the name with an underscore. See EncryptionDataResponse for example

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I updated it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably also change the vars raw_uid and bucket_id to _raw_uid and _bucket_id

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes sense. I updated it.

cls.UID2_API_KEY = os.getenv("UID2_API_KEY")
cls.UID2_SECRET_KEY = os.getenv("UID2_SECRET_KEY")

print(cls.UID2_BASE_URL, cls.UID2_API_KEY, cls.UID2_SECRET_KEY)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary print statement ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, removed it.

self.assertRaises(HTTPError, client.generate_identity_map,
identity_map_input)

def assert_mapped(self, response, ddi):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dii instead of ddi ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I updated it.

# this sample client takes email addresses or phone numbers as input and generates an IdentityMapResponse object
# which contains raw uid or the reason why it is unmapped
# this sample client takes email addresses or phone numbers or hashed versions of either as input and generates
# an IdentityMapResponse object which contains raw uid or the reason why it is unmapped
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment doesn't match what's in _usage()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the comment

self._add_hashed_to_raw_dii_mapping(hashed_normalized_email, email)
self.hashed_normalized_emails.append(hashed_normalized_email)
else: # phone
self.hashed_normalized_phones = []
Copy link
Contributor

@jon8787 jon8787 May 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could the above line go inside the else block at line 27?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I moved it.

Copy link
Contributor

@asloobq asloobq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

self._add_hashed_to_raw_dii_mapping(hashed_normalized_email, email)
self.hashed_normalized_emails.append(hashed_normalized_email)
else: # phone
if already_hashed:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: if already_hashed block should not depend on whether it's an email or phone and should go outside the phone/email check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it depends on the type. If it's a hashed email list, it gets assigned to hashed_normalized_emails, and if it's a hashed phone list, it's assigned to hashed_normalized_phones.

@caroline-ttd caroline-ttd merged commit 3740fd4 into main May 22, 2024
3 checks passed
@caroline-ttd caroline-ttd deleted the ccm-UID2-2760-implement-identity-map branch May 22, 2024 02:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants