-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7cfca34
commit f78859b
Showing
6 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import logging | ||
from typing import Any | ||
|
||
from django.forms import ChoiceField, HiddenInput, Textarea, TextInput | ||
from django.template import Context, Template | ||
from django.utils.safestring import SafeString, mark_safe | ||
|
||
from constance import config | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class ObfuscatedInput(HiddenInput): | ||
def render( | ||
self, | ||
name: str, | ||
value: Any, | ||
attrs: dict[str, str] | None = None, | ||
renderer: Any | None = None, | ||
) -> "SafeString": | ||
context = self.get_context(name, value, attrs) | ||
context["value"] = str(value) | ||
context["label"] = "Set" if value else "Not Set" | ||
|
||
tpl = Template('<input type="hidden" name="{{ widget.name }}" value="{{ value }}">{{ label }}') | ||
return mark_safe(tpl.render(Context(context))) # noqa: S308 | ||
Check warning Code scanning / Bandit Potential XSS on mark_safe function. Warning
Potential XSS on mark_safe function.
Check warning Code scanning / Bandit Use of mark_safe() may expose cross-site scripting vulnerabilities and should be reviewed. Warning
Use of mark_safe() may expose cross-site scripting vulnerabilities and should be reviewed.
|
||
|
||
|
||
class WriteOnlyWidget: | ||
def format_value(self, value: Any) -> str: | ||
return super().format_value("***") | ||
|
||
def value_from_datadict(self, data: dict[str, Any], files: Any, name: str) -> Any: | ||
value = data.get(name) | ||
if value == "***": | ||
return getattr(config, name) | ||
return value | ||
|
||
|
||
class WriteOnlyTextarea(WriteOnlyWidget, Textarea): | ||
pass | ||
|
||
|
||
class WriteOnlyInput(WriteOnlyWidget, TextInput): | ||
pass | ||
|
||
|
||
class GroupChoiceField(ChoiceField): | ||
def __init__(self, **kwargs: Any) -> None: | ||
from django.contrib.auth.models import Group | ||
|
||
ret: list[tuple[str | int, str]] = [(c["name"], c["name"]) for c in Group.objects.values("pk", "name")] | ||
kwargs["choices"] = ret | ||
super().__init__(**kwargs) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import requests | ||
from constance import config | ||
from django import forms | ||
from django.core.exceptions import ValidationError | ||
from django.forms import MultiWidget | ||
from django.forms.widgets import TextInput | ||
|
||
|
||
# https://documenter.getpostman.com/view/20828158/2s93sW7aEc#4fda8a6a-0c21-42b2-a86b-03dce41303ad | ||
class IMTONameEnquiryMultiWidget(MultiWidget): | ||
def __init__(self, *args, **kwargs): | ||
self.widgets = ( | ||
TextInput({"placeholder": "Bank Code"}), | ||
TextInput({"placeholder": "Account Number"}), | ||
TextInput({"placeholder": "Account Full Name"}), | ||
) | ||
super().__init__(self.widgets, *args, **kwargs) | ||
|
||
def decompress(self, value): | ||
return value.rsplit("|") if value else [None, None, None] | ||
|
||
|
||
class IMTONameEnquiryField(forms.fields.MultiValueField): | ||
widget = IMTONameEnquiryMultiWidget | ||
|
||
def __init__(self, *args, **kwargs): | ||
list_fields = [forms.fields.CharField(max_length=16), forms.fields.CharField(max_length=32)] | ||
super().__init__(list_fields, *args, **kwargs) | ||
|
||
def compress(self, values): | ||
return "|".join(values) | ||
|
||
def validate(self, value): | ||
super().validate(value) | ||
try: | ||
account_number, bank_code, account_full_name = value.rsplit("|") | ||
except ValueError: | ||
raise ValidationError("ValueError: not enough values to unpack") | ||
|
||
headers = { | ||
"x-token": config.IMTO_TOKEN, | ||
} | ||
body = {"accountNumber": account_number, "bankCode": bank_code} | ||
response = requests.post(config.IMTO_NAME_ENQUIRY_URL, headers=headers, json=body, timeout=60) | ||
|
||
if ( | ||
response.status_code == 200 | ||
and not response.json()["error"] | ||
and response.json()["code"] == "00" | ||
and response.json()["data"]["beneficiaryAccountName"] == account_full_name | ||
): | ||
return | ||
|
||
if response.status_code == 500: | ||
message = response.reason | ||
elif response.json()["error"]: | ||
message = response.json()["error"] | ||
elif 300 <= response.status_code < 500: | ||
message = f"Error {response.status_code}" | ||
elif response.json()["data"]["beneficiaryAccountName"] != account_full_name: | ||
message = f"Wrong account holder {account_full_name}" | ||
else: | ||
message = "Generic Error" | ||
raise ValidationError(message) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
from unittest.mock import Mock, patch | ||
|
||
import pytest | ||
from django.core.exceptions import ValidationError | ||
|
||
from aurora.core.fields import IMTONameEnquiryField | ||
|
||
|
||
@pytest.mark.django_db | ||
@patch("aurora.core.fields.imto.requests.post") | ||
def test_imto_name_enquiry_ok(mock_post): | ||
mock_post.return_value = Mock( | ||
status_code=200, | ||
json=lambda: { | ||
"message": "operation successful", | ||
"data": { | ||
"lookupParam": "100001241210170958777131925463_DANIEL ADEBAYO ADEDOYIN_22000000051_3", | ||
"beneficiaryAccountNumber": "8168208035", | ||
"beneficiaryBankCode": "100004", | ||
"beneficiaryAccountName": "DANIEL ADEBAYO ADEDOYIN", | ||
}, | ||
"code": "00", | ||
"error": "", | ||
}, | ||
) | ||
fld = IMTONameEnquiryField() | ||
assert fld.validate("bank|account|DANIEL ADEBAYO ADEDOYIN") is None | ||
|
||
|
||
@pytest.mark.django_db | ||
@patch("aurora.core.fields.imto.requests.post") | ||
def test_imto_name_enquiry_ko_not_matching_name(mock_post): | ||
mock_post.return_value = Mock( | ||
status_code=200, | ||
json=lambda: { | ||
"message": "operation successful", | ||
"data": { | ||
"lookupParam": "100001241210170958777131925463_DANIEL ADEBAYO ADEDOYIN_22000000051_3", | ||
"beneficiaryAccountNumber": "8168208035", | ||
"beneficiaryBankCode": "100004", | ||
"beneficiaryAccountName": "DANIEL ADEBAYO ADEDOYIN", | ||
}, | ||
"code": "00", | ||
"error": "", | ||
}, | ||
) | ||
fld = IMTONameEnquiryField() | ||
with pytest.raises(ValidationError, match="Wrong account holder mimmo"): | ||
assert fld.validate("bank|account|mimmo") is None | ||
|
||
|
||
def test_imto_name_enquiry_ko_value_error(): | ||
fld = IMTONameEnquiryField() | ||
with pytest.raises(ValidationError, match="ValueError: not enough values to unpack"): | ||
fld.validate("only_one_value") | ||
|
||
|
||
@pytest.mark.django_db | ||
@patch("aurora.core.fields.imto.requests.post") | ||
def test_imto_name_enquiry_error_status_code(mock_post): | ||
mock_post.return_value = Mock( | ||
status_code=400, | ||
json=lambda: { | ||
"message": "operation successful", | ||
"data": { | ||
"lookupParam": "100001241210170958777131925463_DANIEL ADEBAYO ADEDOYIN_22000000051_3", | ||
"beneficiaryAccountNumber": "8168208035", | ||
"beneficiaryBankCode": "100004", | ||
"beneficiaryAccountName": "DANIEL ADEBAYO ADEDOYIN", | ||
}, | ||
"code": "00", | ||
"error": "", | ||
}, | ||
) | ||
fld = IMTONameEnquiryField() | ||
with pytest.raises(ValidationError, match="Error 400"): | ||
assert fld.validate("bank|account|mimmo") is None | ||
|
||
|
||
@pytest.mark.django_db | ||
@patch("aurora.core.fields.imto.requests.post") | ||
def test_imto_name_enquiry_error_500(mock_post): | ||
mock_post.return_value = Mock( | ||
status_code=500, | ||
reason="Internal Server Error", | ||
json=lambda: { | ||
"message": "operation successful", | ||
"data": { | ||
"lookupParam": "100001241210170958777131925463_DANIEL ADEBAYO ADEDOYIN_22000000051_3", | ||
"beneficiaryAccountNumber": "8168208035", | ||
"beneficiaryBankCode": "100004", | ||
"beneficiaryAccountName": "DANIEL ADEBAYO ADEDOYIN", | ||
}, | ||
"code": "00", | ||
"error": "", | ||
}, | ||
) | ||
fld = IMTONameEnquiryField() | ||
with pytest.raises(ValidationError, match="Internal Server Error"): | ||
assert fld.validate("bank|account|mimmo") is None | ||
|
||
|
||
@pytest.mark.django_db | ||
@patch("aurora.core.fields.imto.requests.post") | ||
def test_imto_name_enquiry_error_error(mock_post): | ||
mock_post.return_value = Mock( | ||
status_code=400, | ||
json=lambda: { | ||
"message": "operation successful", | ||
"data": { | ||
"lookupParam": "100001241210170958777131925463_DANIEL ADEBAYO ADEDOYIN_22000000051_3", | ||
"beneficiaryAccountNumber": "8168208035", | ||
"beneficiaryBankCode": "100004", | ||
"beneficiaryAccountName": "DANIEL ADEBAYO ADEDOYIN", | ||
}, | ||
"code": "00", | ||
"error": "Bad Request", | ||
}, | ||
) | ||
fld = IMTONameEnquiryField() | ||
with pytest.raises(ValidationError, match="Bad Request"): | ||
assert fld.validate("bank|account|mimmo") is None |