diff --git a/Pipfile b/Pipfile index d9cb9335..fc9f4046 100644 --- a/Pipfile +++ b/Pipfile @@ -20,6 +20,7 @@ pyopenssl = "*" requests = "*" apache-libcloud = "*" lockfile = "*" +defusedxml = "*" [dev-packages] bandit = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 006dae19..82fb96d2 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "552b7ac6943559a1fc3be1c4e1c91f965cbfb97c115566051950450c7cd6f78b" + "sha256": "e96fe800085344ee6147c09dc8a3828aa38edd93598c05b72a9944e7b0154616" }, "pipfile-spec": 6, "requires": { @@ -121,6 +121,14 @@ ], "version": "==2.3.1" }, + "defusedxml": { + "hashes": [ + "sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4", + "sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20" + ], + "index": "pypi", + "version": "==0.5.0" + }, "flask": { "hashes": [ "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", @@ -388,17 +396,17 @@ }, "atomicwrites": { "hashes": [ - "sha256:240831ea22da9ab882b551b31d4225591e5e447a68c5e188db5b89ca1d487585", - "sha256:a24da68318b08ac9c9c45029f4a10371ab5b20e4226738e150e6e7c571630ae6" + "sha256:0312ad34fcad8fac3704d441f7b317e50af620823353ec657a53e981f92920c0", + "sha256:ec9ae8adaae229e4f8446952d204a3e4b5fdd2d099f9be3aaf556120135fb3ee" ], - "version": "==1.1.5" + "version": "==1.2.1" }, "attrs": { "hashes": [ - "sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265", - "sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b" + "sha256:10cbf6e27dbce8c30807caf056c8eb50917e0eaafe86347671b57254006c3e69", + "sha256:ca4be454458f9dec299268d472aaa5a11f67a4ff70093396e1ceae9c76cf4bbb" ], - "version": "==18.1.0" + "version": "==18.2.0" }, "backcall": { "hashes": [ @@ -409,11 +417,11 @@ }, "bandit": { "hashes": [ - "sha256:45bf1b361004e861e5b423b36ff5c700d21442753c841013c87f14a4639b1d74", - "sha256:a3aa04802194ec1fd290849e02b915824f9c3234623d7dcea6a33b1605ddb0ac" + "sha256:6102b5d6afd9d966df5054e0bdfc2e73a24d0fea400ec25f2e54c134412158d7", + "sha256:9413facfe9de1e1bd291d525c784e1beb1a55c9916b51dae12979af63a69ba4c" ], "index": "pypi", - "version": "==1.5.0" + "version": "==1.5.1" }, "black": { "hashes": [ @@ -651,10 +659,10 @@ }, "py": { "hashes": [ - "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", - "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" + "sha256:06a30435d058473046be836d3fc4f27167fd84c45b99704f2fb5509ef61f9af1", + "sha256:50402e9d1c9005d759426988a492e0edaadb7f4e68bcddfea586bc7432d009c6" ], - "version": "==1.5.4" + "version": "==1.6.0" }, "pygments": { "hashes": [ @@ -673,11 +681,11 @@ }, "pytest": { "hashes": [ - "sha256:3459a123ad5532852d36f6f4501dfe1acf4af1dd9541834a164666aa40395b02", - "sha256:96bfd45dbe863b447a3054145cd78a9d7f31475d2bce6111b133c0cc4f305118" + "sha256:453cbbbe5ce6db38717d282b758b917de84802af4288910c12442984bde7b823", + "sha256:a8a07f84e680482eb51e244370aaf2caa6301ef265f37c2bdefb3dd3b663f99d" ], "index": "pypi", - "version": "==3.7.2" + "version": "==3.8.0" }, "pytest-env": { "hashes": [ @@ -688,11 +696,11 @@ }, "pytest-flask": { "hashes": [ - "sha256:2c5a36f9033ef8b6f85ddbefaebdd4f89197fc283f94b20dfe1a1beba4b77f03", - "sha256:657c7de386215ab0230bee4d76ace0339ae82fcbb34e134e17a29f65032eef03" + "sha256:be3551e5d8cccd2f26e51fa4268398619be18b9e2300fdab7f4b2aeaeee0a588", + "sha256:d240537c7cfce9f28d0cd2af30f3fb0f452813fbc73cb0518d2e81363ef46112" ], "index": "pypi", - "version": "==0.10.0" + "version": "==0.12.0" }, "pytest-watch": { "hashes": [ @@ -758,9 +766,10 @@ }, "toml": { "hashes": [ - "sha256:8e86bd6ce8cc11b9620cb637466453d94f5d57ad86f17e98a98d1f73e3baab2d" + "sha256:380178cde50a6a79f9d2cf6f42a62a5174febe5eea4126fe4038785f1d888d42", + "sha256:a7901919d3e4f92ffba7ff40a9d697e35bbbc8a8049fe8da742f34c83606d957" ], - "version": "==0.9.4" + "version": "==0.9.6" }, "traitlets": { "hashes": [ @@ -800,9 +809,9 @@ }, "watchdog": { "hashes": [ - "sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162" + "sha256:965f658d0732de3188211932aeb0bb457587f04f63ab4c1e33eab878e9de961d" ], - "version": "==0.8.3" + "version": "==0.9.0" }, "wcwidth": { "hashes": [ diff --git a/atst/eda_client.py b/atst/eda_client.py index 3251499e..b91eb1df 100644 --- a/atst/eda_client.py +++ b/atst/eda_client.py @@ -1,3 +1,10 @@ +from csv import DictReader +import defusedxml.ElementTree as ET + +import requests +from requests.auth import HTTPBasicAuth + + class EDAClientBase(object): def list_contracts( self, @@ -97,8 +104,24 @@ class MockEDAClient(EDAClientBase): class EDAClient(EDAClientBase): - def __init__(self, base_url, user_name, user_role): - pass + def __init__(self, base_url, user_name, user_role, auth_name, auth_pass): + self.base_url = base_url + self.user_name = user_name + self.user_role = user_role + self.auth = HTTPBasicAuth(auth_name, auth_pass) + + def _make_url(self, method, **kwargs): + query_args = dict(kwargs) + query_string = "&".join( + ["{}={}".format(key, value) for key, value in query_args.items()] + ) + return "{base_url}/{method}?{query_string}".format( + base_url=self.base_url, method=method, query_string=query_string + ) + + def _get(self, method, **kwargs): + url = self._make_url(method, **kwargs) + return requests.get(url, auth=self.auth, verify="ssl/server-certs/eda.pem") def list_contracts( self, @@ -107,11 +130,37 @@ class EDAClient(EDAClientBase): cage_code=None, duns_number=None, ): - # TODO: Fetch the contracts CSV and transform them into dictionaries. - # https://docs.python.org/3/library/csv.html#csv.DictReader - raise NotImplementedError() + response = self._get( + "wawf_interface.returnContractList", + pContract=contract_number, + pDelivery_Order=delivery_order, + pCage_Code=cage_code, + pDuns_Number=duns_number, + pUserName=self.user_name, + pUser_Role=self.user_role, + ) + lines = response.text.replace("
", "").split("\n") + return list(DictReader(lines)) def get_contract(self, contract_number, status): - # TODO: Fetch the contract XML and transform it into a dictionary. - # https://docs.python.org/3.7/library/xml.etree.elementtree.html - raise NotImplementedError() + response = self._get( + "pds_contract_interface.get_xml_doc", + pContract=contract_number, + pStatus=status, + ) + if response.text.startswith("No data found"): + return None + return ET.fromstring(response.text) + + def get_clins(self, record_key, clins, cage_code="", duns_number=""): + response = self._get( + "wawf_interface.returnclinXML", + pCage_Code=cage_code, + pDuns_Number=duns_number, + pUserName=self.user_name, + pUser_Role=self.user_role, + pRecord_key=record_key, + pClins=clins, + ) + # TODO: Parse XML, similar to `get_contract` + return response diff --git a/script/example_fetch_from_eda.py b/script/example_fetch_from_eda.py new file mode 100644 index 00000000..8425f3c8 --- /dev/null +++ b/script/example_fetch_from_eda.py @@ -0,0 +1,35 @@ +# Add root project dir to the python path +import os +import sys + +parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +sys.path.append(parent_dir) + +from atst.app import make_config, make_app +from atst.eda_client import EDAClient + + +config = make_config() + +client = EDAClient( + base_url=config.get("EDA_HOST"), + user_name=config.get("EDA_USER_NAME"), + user_role=config.get("EDA_USER_ROLE"), + auth_name=config.get("EDA_AUTH_NAME"), + auth_pass=config.get("EDA_AUTH_PASS"), +) + +contract_number = "DCA10096D0052" + +listed = client.list_contracts( + contract_number=contract_number, + delivery_order="", + cage_code="1U305", + duns_number="", +) +contract = client.get_contract(contract_number=contract_number, status="Y") + +requested_clins = ",".join(["'0001'", "'0003'", "'1001'", "'1003'", "'2001'", "'2003'"]) +clins = client.get_clins( + record_key=contract_number, duns_number="", cage_code="1U305", clins=requested_clins +) diff --git a/ssl/server-certs/eda.pem b/ssl/server-certs/eda.pem new file mode 100644 index 00000000..41b8f0c3 --- /dev/null +++ b/ssl/server-certs/eda.pem @@ -0,0 +1,50 @@ +-----BEGIN CERTIFICATE----- +MIIEyTCCA7GgAwIBAgIBCzANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJVUzEY +MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT +A1BLSTEbMBkGA1UEAxMSRG9EIEpJVEMgUm9vdCBDQSAzMB4XDTE1MTAyNjAwMDAw +MFoXDTIxMTAyNjAwMDAwMFowYjELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4g +R292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQLEwNQS0kxHTAbBgNVBAMT +FERPRCBKSVRDIElEIFNXIENBLTM3MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAwIInyKWn2FQj6HgRf8CvTEt3iFE0Ln88S/tceBZ6XZJc+NyOVCB9Glfv +mgA/uXNKjQeivmol0MibvUvZMhKjJXiPoPc6bH978xBKQGDN/8m/E49qArIvL/Qj +puDYChX9aAp78xM4l/49xHtOwxmxZe/85AKH6tWSGL8aCFiGnVqv4oWnDBI80ZTY +bgRjbsm60nvAFU0VMmJJasmPEvX3OPQThqsxj4cC/y0IXlVdW6tDrSNuQmGyr2MV +dVLPN1LsTHDGX242JYiSo9Uoa0YeYL1icNN0NEnj7hVyfL48GHsUV4B2HHNe6Hmh +vHpPjUPnyiaqQPrtgpBnigfl+XurAwIDAQABo4IBijCCAYYwHwYDVR0jBBgwFoAU +8K69SjouIlHowoy+zvekatI0qsUwHQYDVR0OBBYEFAO8i/Knl7OOIoujUiu9ZU7H +tGTJMA4GA1UdDwEB/wQEAwIBhjBMBgNVHSAERTBDMAsGCWCGSAFlAgELJDALBglg +hkgBZQIBCycwCwYJYIZIAWUCAQsqMAwGCmCGSAFlAwIBMAswDAYKYIZIAWUDAgEw +DTASBgNVHRMBAf8ECDAGAQH/AgEAMAwGA1UdJAQFMAOAAQAwPwYDVR0fBDgwNjA0 +oDKgMIYuaHR0cDovL2NybC5uaXQuZGlzYS5taWwvY3JsL0RPREpJVENST09UQ0Ez +LmNybDCBggYIKwYBBQUHAQEEdjB0MEIGCCsGAQUFBzAChjZodHRwOi8vY3JsLm5p +dC5kaXNhLm1pbC9pc3N1ZWR0by9ET0RKSVRDUk9PVENBM19JVC5wN2MwLgYIKwYB +BQUHMAGGImh0dHA6Ly9vY3NwLm5zbjAucmN2cy5uaXQuZGlzYS5taWwwDQYJKoZI +hvcNAQELBQADggEBABBdos0wWNuFFUx66x3/HJDecFeVSKH5DCA4Wq9UHjEnIJU8 +iHDJmmATX6eav7eM1ly+sOYdSvVNQ7Wm+TTTuQejCk6YfQP9VlbTj1zDWSP88QQg +Xb7TWp1D7yvYDdZUtj0Zo+REnUX1c0rew0fQYpc9GylBJog3QVZx++U37ZShgdDC +ScC7mUe7c/cHcdOgV45uG7MBV7bWAZgfWXZ1G4WXs51PGec2SXYK87LuSIzGWCaK +xbdnnLuSjWTqk5jx12YNgbdHN6dbahQi5ZqXy66kfXGMoE5YqMVOAUmu3Eh7PJvl +MDbWz/YvtMTS0iFXmQpkzv+A5Hs3iXiGw9IweE4= +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBATANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJVUzEY +MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT +A1BLSTEbMBkGA1UEAxMSRG9EIEpJVEMgUm9vdCBDQSAzMB4XDTEyMDMwNTIzMzc1 +OFoXDTI5MTIzMDIzMzc1OFowYDELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4g +R292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQLEwNQS0kxGzAZBgNVBAMT +EkRvRCBKSVRDIFJvb3QgQ0EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMUjrv4319cGrN8e9FvMixEaog7YChfRqX4SuBmQDr1hbnqZWNun8s0BBN2v +SBBNOwBA+98BSs/J/B1fKiVIZ8+cL7zbxSWx0d6irvOwid0YudFFoh75FRQjegpT +AVe6cwr5PJvGuOTF0LPs87y3vUpyHsGDje017as0Vl/K6ONxzEQXxRdP5QE0iZn4 +dyIyD4AbRy21GYaMNah7LaJqmspr9Bxovt25IcoplITfXWz1xBvkJF0ME+Yq4D7m +Idhd5ijEyuY14s3eVS04adf5C8A09ujfuDhIFl/a+36AQ87PHDA4DnLzLaylxunZ +Eq13bJ8J6cyVSvpeoqtjX4g7ZFcCAwEAAaNCMEAwHQYDVR0OBBYEFPCuvUo6LiJR +6MKMvs73pGrSNKrFMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4IBAQCzdpjOnkhdGaGlCuIl2Vz6RARvx5876JpS4Sj+uGWJ +3AO0g83cCsBkpNDpKt/7Sgq8lQCnxCk+wYBkrbdMXmNUEm7grR9qP/V+fTJ/Z/pg +eeG1HITS5pvWITP9hojKi/8XEdPMo7ALWYDq2JZCj8aUY9AD6zjXiYNQEDSqAd9k +EvvjPgYIjqXAZTAC9XRgFPxvnExU06z8jjKtts7ULLspGwO7SjhrspaBpqg4H3xC +l9sdEpzbn/OcGJk/JUon8wR/ZhGtMn2LVf1i85uUi+MMtVijEpMVyQOjbo4bl+Go +h4MIvAqGepljwBs++m76JSzILSSMdiwxlNqbjFtcCAp6 +-----END CERTIFICATE-----