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

Make IP address optional when reporting transactions #141

Merged
merged 5 commits into from
Jun 12, 2024

Conversation

ugexe
Copy link
Contributor

@ugexe ugexe commented May 24, 2024

No description provided.

@ugexe
Copy link
Contributor Author

ugexe commented May 28, 2024

There seem to be tox failures in this branch that also exist on the latest commit in the main branch 🤔

Comment on lines 401 to 419
def validate_at_least_one_identifier_field(report):
optional_fields = ["ip_address", "maxmind_id", "minfraud_id", "transaction_id"]
if not any(field in report for field in optional_fields):
raise ValueError("The report must contain at least one of the following fields: 'ip_address', 'maxmind_id', 'minfraud_id', 'transaction_id'.")
return True
Copy link
Member

Choose a reason for hiding this comment

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

Would something like this work instead:

id_schema = Schema(
  {
    Required(
      Any("ip_address", "maxmind_id", "minfraud_id", "transaction_id"), 
      msg="The report must contain at least one of the following fields: 'ip_address', 'maxmind_id', 'minfraud_id', 'transaction_id'.",
    )
  },
  extra=ALLOW_EXTRA,
)

validate_report = All(validate_report_schema, id_schema)

It might also be good to prefix everything we don't intend to be public with an underscore.

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'm not sure that we can. It'd have to be more like having a schema for validating the keys, and another schema for validating the values. For example this does not work:

_report_schema = Schema(
    {
        "chargeback_code": str,
        "ip_address": _ip_address,
        "maxmind_id": _maxmind_id,
        "minfraud_id": _uuid,
        "notes": str,
        "tag": _tag,
        "transaction_id": _transaction_id,
    },
)

_report_required_schema = Schema(
    {
        Required(
            Any("ip_address", "maxmind_id", "minfraud_id", "transaction_id"),
            msg="The report must contain at least one of the following fields: 'ip_address', 'maxmind_id', 'minfraud_id', 'transaction_id'.",
        ): object,
    },
    extra=ALLOW_EXTRA,
)

validate_report = All(_report_schema, _report_required_schema)

It gives errors for various tests like this:

./test_validation.py::TestReport::test_ip_address Failed: MultipleInvalid The report must contain at least one of the following fields: 'ip_address', 'maxmind_id', 'minfraud_id', 'transaction_id'. @ data['tag'] thrown for {'ip_address': '182.193.2.1', 'tag': 'chargeback'}
  File "/home/nlogan_maxmind_com/minfraud-api-python/tests/test_validation.py", line 66, in check_report_no_setup
    validate_report(report)

We can see ip_address was indeed sent but the validation is not seeing it. The following does work:

_report_schema = Schema(
    {
        "chargeback_code": str,
        "ip_address": _ip_address,
        "maxmind_id": _maxmind_id,
        "minfraud_id": _uuid,
        "notes": str,
        "tag": _tag,
        "transaction_id": _transaction_id,
    },
)

_report_required_schema = Schema(
    {
        "chargeback_code": object,
        "notes": object,
        "tag": object,
        Required(
            Any("ip_address", "maxmind_id", "minfraud_id", "transaction_id"),
            msg="The report must contain at least one of the following fields: 'ip_address', 'maxmind_id', 'minfraud_id', 'transaction_id'.",
        ): object,
    },
)

validate_report = All(_report_schema, _report_required_schema)

To me this suggests we would have to (re)define the optional fields in each schema used with All(...). alecthomas/voluptuous/issues/126#issuecomment-326487353 seems to align with that. I

Copy link
Member

Choose a reason for hiding this comment

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

Weird. I would have expected that to work. I should have tested it. Your tests do pass for me with this though:

validate_report = Schema(
    {

        Any(Required("ip_address"), Required("maxmind_id"), Required("minfraud_id"), Required("transaction_id")): str, 
        "chargeback_code": str,
        "ip_address": _ip_address,
        "maxmind_id": _maxmind_id,
        "minfraud_id": _uuid,
        "notes": str,
        Required("tag"): _tag,
        "transaction_id": _transaction_id,
    },
)

I haven't looked too closely besides running the tests.

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 doesn't seem to give a validation error when only tag is supplied. I had to add a new test to catch this though

diff --git a/tests/test_validation.py b/tests/test_validation.py
index 87084ae..b905285 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -439,6 +439,7 @@ class TestReport(unittest.TestCase, ValidationBase):
             self.check_invalid_report({"tag": bad})

     def test_report_valid_identifier(self):
+        self.check_invalid_report_no_setup({"tag": "chargeback"})
         self.check_report_no_setup({"tag": "chargeback", "ip_address": "1.1.1.1"})
         self.check_report_no_setup({"tag": "chargeback", "minfraud_id": "58fa38d8-4b87-458b-a22b-f00eda1aa20d"})
         self.check_report_no_setup({"tag": "chargeback", "maxmind_id": "12345678"})

Copy link
Member

Choose a reason for hiding this comment

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

It seems like there should be some way to do it, but I don't know that we need to dwell on that here. It would be worth adding that test case to this API and the other APIs if relevant.

def validate_report(report):
validate_report_schema(report)
validate_at_least_one_identifier_field(report)
return True
Copy link
Member

Choose a reason for hiding this comment

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

Missing a newline at the end of this file.

@ugexe ugexe force-pushed the nlogan/no-ip-report branch 4 times, most recently from e9c7152 to 895ec73 Compare June 5, 2024 23:03
@@ -13,7 +13,7 @@
from voluptuous import MultipleInvalid

from .errors import InvalidRequestError
from .validation import validate_report, validate_transaction
from .validation import _validate_report, _validate_transaction
Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I didn't mean that we should add an underscore to these. I just meant the intermediate functions that you added that are only used in that file.

Comment on lines +402 to +412
optional_fields = ["ip_address", "maxmind_id", "minfraud_id", "transaction_id"]
if not any(field in report for field in optional_fields):
Copy link
Member

Choose a reason for hiding this comment

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

This is probably bikeshedding, but expressing it as a set operation seems a bit simpler to me:

Suggested change
optional_fields = ["ip_address", "maxmind_id", "minfraud_id", "transaction_id"]
if not any(field in report for field in optional_fields):
optional_fields = {"ip_address", "maxmind_id", "minfraud_id", "transaction_id"}
if not optional_fields & report.keys():

Copy link
Member

Choose a reason for hiding this comment

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

That said, maybe we should handle the empty string for these too like we do for the other APIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The individual field validation that exists should already disallow empty strings for all of these fields. The only one we might need to check is minfraid_id to disallow the zero UUID

@oschwald oschwald merged commit 015d70a into main Jun 12, 2024
25 checks passed
@oschwald oschwald deleted the nlogan/no-ip-report branch June 12, 2024 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants