From 9b03af22f3d74aff6e87533846245c38f732d958 Mon Sep 17 00:00:00 2001 From: Maxwell Austensen Date: Fri, 2 Feb 2024 18:05:24 -0500 Subject: [PATCH 1/3] add tests and error validation for alert endpoints --- project/settings_pytest.py | 1 - requirements-dev.txt | 2 +- tests/data/oca_metadata.csv | 101 +++++++++++++++++++++++++++++++++++ wow/forms.py | 72 ++++++++++++++++++++++--- wow/tests/test_views.py | 102 +++++++++++++++++++++++++++++++++++- wow/views.py | 42 ++++++++------- 6 files changed, 291 insertions(+), 29 deletions(-) create mode 100644 tests/data/oca_metadata.csv diff --git a/project/settings_pytest.py b/project/settings_pytest.py index 4feafd5ed..b43d8df2d 100644 --- a/project/settings_pytest.py +++ b/project/settings_pytest.py @@ -4,7 +4,6 @@ os.environ["DEBUG"] = "" os.environ["SECRET_KEY"] = "for testing only!" -os.environ["ALERTS_API_TOKEN"] = "test_token" from .settings import * # noqa diff --git a/requirements-dev.txt b/requirements-dev.txt index 908c5e9b4..4884912e1 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,5 @@ -r requirements.txt -https://github.com/nycdb/nycdb/archive/fc7fa7a4bd1fb33a50fbc189992878761182ab13.zip#subdirectory=src +https://github.com/nycdb/nycdb/archive/4d3ec9d90db0c378a8a35a53a96a0c23133f85fa.zip#subdirectory=src mypy==0.782 PyYAML>=5.1 pytest==6.2.5 diff --git a/tests/data/oca_metadata.csv b/tests/data/oca_metadata.csv new file mode 100644 index 000000000..dbf9c36d7 --- /dev/null +++ b/tests/data/oca_metadata.csv @@ -0,0 +1,101 @@ +indexnumberid,initialdate,updatedate,deletedate +00000131D2D43B62D4764607D1AB017FC536618A72F3795716341A8DD100CBEF,2021-06-14,2021-06-14, +00004F2E7DAB045528218F5837BD211819EAD1ECB1859D8962EF03A55AB44B4A,2021-06-14,2021-06-14, +000058EF368DF4A687DC20231F9E2AB72D59C718960F15A2C68408D052CD99BF,2021-06-14,2021-06-14, +0000A75A9F1A448C03176A193D73CC3A953AB09580781CB1FD3785D42D4F8785,2021-06-14,2021-06-14, +0000C04F9AECEA3F8CAB8F243FBFC0AE6E411395633A550D08BC7517F3189A16,2021-06-14,2021-06-14, +000146FB4347DEDD75BD9817F6FA786E6B978ACA16FA54CAEDD5D48B16DD53E5,2021-06-14,2021-06-14, +00014B9621814EC3EDA1C1E4201156CB8BDF3B201B76362104AD5095D580964F,2021-06-14,2021-06-14, +00016F2990994099BA0469512D447C28F05C142023FF09FBD94203EE52C550F4,2021-06-14,2021-06-14, +000193AB710E71698AF7E6B0632BA3529817BD1FA82C5B5F53F5C8C927FB884A,2021-06-14,2021-06-14, +00020255C95F299D961FDB3373F8580E1CD2E59F6CB78C278D30FEB1B4109F50,2021-06-14,2021-06-14, +0002048426D4BD92C51E1CEBF71D99B24E1816F0DA4F9F1D484ABDABA56768B4,2021-06-14,2021-06-14, +00022B7A78BB092A63BE77B6A2E61D07C1F922AB24DE6186145526544991E2FD,2021-06-14,2021-06-14, +00022B9CA6D74E9A4227B530BB59362322D9BEF109D244CCED83D82A2AE10DE9,2021-06-14,2021-06-14, +00024A3C8EA22DFDBB6F52202F232D464B55553932C842CC21860AF9088B5D99,2021-06-14,2021-06-14, +00024AEB5EF3CCA1AC7198D6C6ECB8082CEF5DD5A65567B3C300DE06582B956A,2021-06-14,2021-06-14, +0002A3534D6E34F2532448D8858B14C7795364581524239A96E71510918D1234,2021-06-14,2021-06-14, +0002C6D1E3D66441D2443770AFC1BF401059031DA2D56A639D07A61816394B2A,2021-06-14,2021-06-14, +0002CFEE0F786F6A240A7C992686E96F08BE94A81B0C8AD751AF817EA16FED51,2021-06-14,2021-06-14, +0002D44FC1BF26BFE9A1756F74286AB2AB7EB3064933A4FDF2AE069B3B8F8C9F,2021-06-14,2021-06-14, +00035EBC87AE2AE6CCC845418F34FFB465CA5DF0509AF23DA70D397986832E26,2021-06-14,2021-06-14, +00036AED9C4262030B393EC4125B992180A417C4269B30A2668572A1EBE6B5BA,2021-06-14,2021-06-14, +0003D0ECC04ADC1BC1436AD556BF169897F3ECF334AC94B31D8A7038564275E3,2021-06-14,2021-06-14, +0003DECD298A8ACD81882DF362778C97B221B8C2BC93CDE01F1512F915A357C3,2021-06-14,2021-06-14, +0003F1B213FCCE7C4FC2DCA63CF8692819549D3CD01836ADEB39F1D31DD5004A,2021-06-14,2021-06-14, +0004230AEC435121DBB871300EB630BA3CCCA9B2E97F55E14C54EFE4C2F2A3C9,2021-06-14,2021-06-14, +00045DE3682E987A5F1032D3479CEEB899D1F1ED1841DA11A2C6E973766AF5F2,2021-06-14,2021-06-14, +000496E4C97929A6183AB728793EEA4417114024C44328670A028F79E5645263,2021-06-14,2021-06-14, +0004E8259DF88F82230E77F4BB4815CA999E2B93AF1B18B86CBE7380ADA97810,2021-06-14,2021-06-14, +000533BB95BB40ED8B0A71F37302E3C6722A333A7A2FAEF40A09E824722DFD80,2021-06-14,2021-06-14, +000549E291656DDF1346A04732606C7B76427D60822E4B2DBB483F24D2A0B252,2021-06-14,2021-06-14, +000577E7AF3F91AAE0DDA76F3887A563ED858A51E6D0154D7BBB226403AF8FDA,2021-06-14,2021-06-14, +00058680E9A4C1743357344B79DB8D7CEB1A1C717656A313CDCEEBC8921E0140,2021-06-14,2021-06-14, +0005CF64B29D3DEB09A60A7349A48CFE0C44A1CF02DE11999C1DE994F97DDCD6,2021-06-14,2021-06-14, +0005CFF05CE21AD213883B3357E83D129C8475D3C7722CCE3A7A4AA596374F58,2021-06-14,2021-06-14, +0005E1F7E257B763834A99C2CF7445066D0C36EA089384CB479DB3B1D186099E,2021-06-14,2021-06-14, +00072E1B3BF02F1E734E1C36D9A485AA29AA5A1BE0E8D72A55B57C30ABAC1541,2021-06-14,2021-06-14, +00076AEAE7F558814A919207F7C3423D00A1BBD5A91CE57A0EB61C84CA34EE3F,2021-06-14,2021-06-14, +000786303D7B1ED121DBC00E5B51BE46A9AD54279E1791E802A03A0C706201A0,2021-06-14,2021-06-14, +00078C9DCA0F51693D239140CCF94B94D848C3BBBC091F356FB35B53583A49BB,2021-06-14,2021-06-14, +00079D75FEFDD0B0366BB945CC506A369E5B51B3744E065080EB2FB70E9749A1,2021-06-14,2021-06-14, +0007F719F8FB917B10442D969115F8DD31D9670A9EA9CDE2F41C84C64181FDB6,2021-06-14,2021-06-14, +0007F74F7E4D49665B7E5F6A447B485663939476858627A2FC7C33521CDEA247,2021-06-14,2021-06-14, +000822F96B7A072E925601F52FF3B1057D13303A55D4E43EFF9687D67048CADE,2021-06-14,2021-06-14, +00084DE8D849AB2F79406E4B589FBBF0F6C92CD7A28317681144C1726CE5183C,2021-06-14,2021-06-14, +000853A71757FDD263FC350941772B4853522733479ABE171F3E58DE732993E7,2021-06-14,2021-06-14, +00089EC027CB5B918B5A06F169B27B31B29DD0FB30C21B7F5AEF54784154581C,2021-06-14,2021-06-14, +0008D802F5E44BA4F9AD1415E0374AF3CECFE7FF213B321D002D4E0580E713A0,2021-06-14,2021-06-14, +0008E9945F006F2545E186230A99DDAF1E3C788B1516185E6D7622000442431B,2021-06-14,2021-06-14, +00092AA9B4321428B5814DC8A004498525F750B97F52E377A1F0E6687A5D192D,2021-06-14,2021-06-14, +000940C90EDA3DDFB257CE8426608CB96CC813D3B5D78133D0F79F57CAE2F5B0,2021-06-14,2021-06-14, +00099CC61F8135771452434803991B99FA1C34ADF0038F534303F8C569C259AE,2021-06-14,2021-06-14, +0009A51F311270B08CE652A4D4D2EBF6E69C974A4695D9360376C5E3C773C5D9,2021-06-14,2021-06-14, +0009B1769F4E252525CF15B8260CAB8A439419DD6FDEB6B4134D6792CCA4F1A5,2021-06-14,2021-06-14, +0009B5D68832AEDEC07C46B0DFB97792C620AC38EBB6EFC9E8B11B234831C69A,2021-06-14,2021-06-14, +0009DCC02350FCC49B29B568F96EF094CC9237C35CAA7364B490F27526DF48DA,2021-06-14,2021-06-14, +0009EEF71FE328EC4D0285A40E86E9F29703EF9880730D7D56385416D8FB530A,2021-06-14,2021-06-14, +000A4082E905245377D75D52A8AA0FFD3D0364CBB37121FC53363CE337987E3C,2021-06-14,2021-06-14, +000A7164EE030AD5A819FE40E120EDAB16C40E3EE8E5CDBEE42D87E177C9BA90,2021-06-14,2021-06-14, +000A8A771BD5E97DEAB466893C989C60133A7CBF30B3FE282E4550F937A1F757,2021-06-14,2021-06-14, +000A9B977D3187238B0EB71EE80DA7BC5A11E9F7F8BCADBCB2F5E5444F8E6819,2021-06-14,2021-06-14, +000ACF01F908046E0690CE817A6A41CA65450CD9DB61B10D8981E59A6EC28623,2021-06-14,2021-06-14, +000B36BEC9CAF2423643EF5D952C2810F18AFB403B7E0B3D6D3E1E140B71D9B0,2021-06-14,2021-06-14, +000B37348B76E21E5C9C54240291BDAFA9F80F6739A1DE58E1949557156DE36E,2021-06-14,2021-06-14, +000B671F47D389777384371071177A2BAA116BAD42D8A2A3B571A7CB7E143111,2021-06-14,2021-06-14, +000B982FA71179417BCC7468BDE3E5EA1C0841D10290CEC86E82A707100A666F,2021-06-14,2021-06-14, +000BFE54AD744E9AAB0F6F407470F1D839DBB98CDDF52E1B2598978B21F9BA06,2021-06-14,2021-06-14, +000C1C61085220D1D2E12D834DE8B727BB31DAC3935CDA17D110F04474DDDE81,2021-06-14,2021-06-14, +000CD8CB40B45DF6689BD5A546BF14BAFC0EC6B77976AF8FE5F7BF122CE76A50,2021-06-14,2021-06-14, +000D2799477E941265964999DAFE8C68453E97ABCE1429E8AD03BBFAFA58C8AC,2021-06-14,2021-06-14, +000D2A335F779E66946A6441EEEC7CFF711C451842FD7846006B637E6F4F3E35,2021-06-14,2021-06-14, +000D37E1EE74159269302BBD22B5B01D8D5F874791D8F85EE3E468C54636177E,2021-06-14,2021-06-14, +000B4086E7ABCC5F5A8D53CA084CEE69C2D84A203477A4B1522F9E2F306E5BA2,2021-06-14,2022-10-02, +000B20C9739E1AB44CCFC35542196DBA273F4B4F4EA8CF6E7A6C4977B7B95CD3,2021-06-14,2021-10-24, +0003ABC40319F5D6E8A1C806FDB070938547ADAD901195CC78C7ECC92E744FDA,2021-06-14,2022-01-23, +000D6495F87AD7E2834E3A786B0BE563F93FAF011E02F1D4700E7DC1B90140AA,2021-06-14,2021-06-14, +000D68FCFF07F38BA42F484F4A20D23BC977BDE2C239217ED86ADB4E7DEA8FE4,2021-06-14,2021-06-14, +000D78DB6C1484E6F1688384A7DF19D3A036CB0C0B94D84865B9F4809A42CF97,2021-06-14,2021-06-14, +000D9F5A86E8943AFCA56223B6993807669DE571BA5800AED5510FFC7823D7F7,2021-06-14,2021-06-14, +000DA650C2331A07CD80A8291B6C8673EAF22CD52F663C4254466915800A0883,2021-06-14,2021-06-14, +000DA763F2552B4E00876AE0C1A04DF1D0BC74919D12E246721AEFB795F43339,2021-06-14,2021-06-14, +000DF6D4389700C19A81C36098CC5642BEA01EAC4C37B5C7334AEA57E4D15A3B,2021-06-14,2021-06-14, +000E2F84C70A5AFD033F26F97233518C64B68798453206731D3A1BCDFFE8E12B,2021-06-14,2021-06-14, +000EDB4206D11AB06D5F914B60B8281065E3533674E42A49B2186049A30C8A5C,2021-06-14,2021-06-14, +000EE95059821AA5069FA828F3D95E70EA1812B955ED7E75A71F0482A63178B1,2021-06-14,2021-06-14, +000F02845A9DDA64B6B73462531AAB307F2D54818D14E91551FD42990AEC1334,2021-06-14,2021-06-14, +000F362CEBA95B6CF8747B0B589A7DAF0D43E81FF6E5B45C33F9C09A3F775691,2021-06-14,2021-06-14, +000F623FF6EE28A42930DE1A9B56D108289B9714E10D362B2CE06B06DA9E7B2C,2021-06-14,2021-06-14, +000F6682B60159A62DCAD79EE0E1C33CD4812CF35FB6875FB61C622956D701AF,2021-06-14,2021-06-14, +000FE252F426582AA7DA7B0C4F2E7130075158BE3D52440A05B4B0C50077DE5C,2021-06-14,2021-06-14, +00101C3A2DB6479868532CC3CE2E31B2FD259DD301B6F06DF6EFDFE9DA1D0F60,2021-06-14,2021-06-14, +00105016EB49EA9CEAA42125FA617E37FD3CDEE9724BACE399859910E91D61B0,2021-06-14,2021-06-14, +0010F56B72AF939288E644B781CC04C1754753F5DDAE2CE17D0AAC3855E6B83B,2021-06-14,2021-06-14, +001130D5D68636A689DE848B30259BB96821319CC91DA8EC4AE69585886CA7F7,2021-06-14,2021-06-14, +001139C864D6E5FF907B99ADACA14A77B87A7E01F747A0DCBDB1341AAD0EB0FD,2021-06-14,2021-06-14, +00114C9D2C3E310566277721471B8AA9F4764C0F2E0F0A0133CDF64DC8DDEB5B,2021-06-14,2021-06-14, +00118EC7835BF34DCA1609408BB61534C259213F2BE2C7C611DA753AB3E387D4,2021-06-14,2021-06-14, +0011980F5F4CEEB4B829B6FD336D88A932E791D2B4BF3D50F51654989D0A6172,2021-06-14,2021-06-14, +0011B698249B33DE89CD77A9ED41C77BEE08A4394FD76724EA36F45692B4C8AA,2021-06-14,2021-06-14, +00120ADDF4356A6641D9891DD1BAEA6E49E6294798153FCE34CE07D611A8D527,2021-06-14,2021-06-14, +001214779E03E8570C79FCF8BBF7820F897A07DC6EAE44CB229DF716AD0F4266,2021-06-14,2021-06-14, diff --git a/wow/forms.py b/wow/forms.py index 0f5b56f8d..5aa567637 100644 --- a/wow/forms.py +++ b/wow/forms.py @@ -64,11 +64,20 @@ def validate_indicators(value): if i not in valid_indicators: raise ValidationError( "Indicators must be comma-separated list of: 'violations',\ - 'complaints', or 'eviction_filings'" + 'complaints', 'eviction_filings', or 'lagged_eviction_filings'" ) -class EmailAlertForm(PaddedBBLForm): +class EmailAlertViolationsForm(PaddedBBLForm): + start_date = forms.DateField(input_formats=["%Y-%m-%d"]) + end_date = forms.DateField(input_formats=["%Y-%m-%d"]) + + +class EmailAlertLaggedEvictionFilingsForm(PaddedBBLForm): + prev_date = forms.DateField(input_formats=["%Y-%m-%d"]) + + +class EmailAlertSingleIndicatorForm(PaddedBBLForm): indicator = forms.CharField( validators=[ RegexValidator( @@ -76,10 +85,57 @@ class EmailAlertForm(PaddedBBLForm): message="This must be one of 'violations', 'complaints', 'eviction_filings', \ 'lagged_eviction_filings'.", ) - ], - required=False, + ] ) - indicators = CommaSeparatedField(validators=[validate_indicators], required=False) - start_date = forms.DateField(input_formats=["%Y-%m-%d"]) - end_date = forms.DateField(input_formats=["%Y-%m-%d"]) - prev_date = forms.DateField(input_formats=["%Y-%m-%d"]) + start_date = forms.DateField(input_formats=["%Y-%m-%d"], required=False) + end_date = forms.DateField(input_formats=["%Y-%m-%d"], required=False) + prev_date = forms.DateField(input_formats=["%Y-%m-%d"], required=False) + + def clean(self): + data = self.cleaned_data + indicator = data.get("indicator", None) + + if indicator == "lagged_eviction_filings" and not data.get("prev_date", None): + raise forms.ValidationError( + "prev_date is required for lagged_eviction_filings" + ) + elif indicator != "lagged_eviction_filings": + if not data.get("start_date", None): + raise forms.ValidationError( + "start_date is required for violations, complaints, and eviction_filings" + ) + if not data.get("end_date", None): + raise forms.ValidationError( + "end_date is required for violations, complaints, and eviction_filings" + ) + else: + return data + + +class EmailAlertMultiIndicatorForm(PaddedBBLForm): + indicators = CommaSeparatedField(validators=[validate_indicators]) + start_date = forms.DateField(input_formats=["%Y-%m-%d"], required=False) + end_date = forms.DateField(input_formats=["%Y-%m-%d"], required=False) + prev_date = forms.DateField(input_formats=["%Y-%m-%d"], required=False) + + def clean(self): + data = self.cleaned_data + indicators = data.get("indicators", []) + start_end_indicators = ["violations", "complaints", "eviction_filings"] + + if "lagged_eviction_filings" in indicators: + if not data.get("prev_date", None): + raise forms.ValidationError( + "prev_date is required for lagged_eviction_filings" + ) + if not set(start_end_indicators).isdisjoint(indicators): + if not data.get("start_date", None): + raise forms.ValidationError( + "start_date is required for violations, complaints, and eviction_filings" + ) + if not data.get("end_date", None): + raise forms.ValidationError( + "end_date is required for violations, complaints, and eviction_filings" + ) + else: + return data diff --git a/wow/tests/test_views.py b/wow/tests/test_views.py index f9f69943e..aaa62007f 100644 --- a/wow/tests/test_views.py +++ b/wow/tests/test_views.py @@ -3,6 +3,7 @@ from io import StringIO from django.urls import path from django.test import Client +from django.conf import settings import pytest from wow.apiutil import api @@ -25,13 +26,16 @@ def server_error(request): ] +AUTH_ARG = {"HTTP_AUTHORIZATION": f"Token {settings.ALERTS_API_TOKEN}"} + + class ApiTest: HTTP_400_URLS: List[str] = [] def test_400s_work(self, db, client): assert self.HTTP_400_URLS, "No HTTP 400 examples to test!" for url in self.HTTP_400_URLS: - res = client.get(url) + res = client.get(url, **AUTH_ARG) assert res.status_code == 400, f"{url} should return HTTP 400" assert res.json()["error"] == "Bad request" assert "Access-Control-Allow-Origin" in res @@ -134,6 +138,102 @@ def test_it_works(self, db, client): assert res.json()["result"] is not None +class TestAlertsViolations(ApiTest): + HTTP_400_URLS = [ + "/api/alerts/violations", + "/api/alerts/violations?bbl=bop", + "/api/alerts/violations?bbl=3012380016&start_date=2024-01-01", + "/api/alerts/violations?bbl=3012380016&start_date=2024-01-01&end_date=01-07-2024", + ] + + def test_it_works(self, db, client): + res = client.get( + "/api/alerts/violations?bbl=3012380016&start_date=2024-01-01&end_date=2024-01-07" + ) + assert res.status_code == 200 + assert res.json()["result"] is not None + + +class TestAlertsOcaLaggedFilings(ApiTest): + HTTP_400_URLS = [ + "/api/email_oca_lag", + "/api/email_oca_lag?bbl=bop", + "/api/email_oca_lag?bbl=3012380016", + "/api/email_oca_lag?bbl=3012380016&prev_date=01-07-2024", + ] + + def test_it_works(self, db, client): + res = client.get( + "/api/email_oca_lag?bbl=3012380016&prev_date=2024-01-07", **AUTH_ARG + ) + assert res.status_code == 200 + assert res.json()["result"] is not None + + def test_auth_works(self, db, client): + res = client.get("/api/email_oca_lag?bbl=3012380016&prev_date=2024-01-07") + assert res.status_code == 401 + + +class TestAlertsSingleIndicator(ApiTest): + HTTP_400_URLS = [ + "/api/email_alerts", + "/api/email_alerts?bbl=bop", + "/api/email_alerts?bbl=3012380016&indicator=lagged_eviction_filings", + "/api/email_alerts?bbl=3012380016&indicator=violations&start_date=2024-01-01", + "/api/email_alerts?bbl=3012380016&indicator=complaints&end_date=2024-01-01", + "/api/email_alerts?bbl=3012380016&indicator=eviction_filings&end_date=2024-01-01", + ] + + def test_it_works(self, db, client): + urls = [ + "/api/email_alerts?bbl=3012380016&indicator=lagged_eviction_filings&prev_date=2024-01-07", + "/api/email_alerts?bbl=3012380016&indicator=violations&start_date=2024-01-01&end_date=2024-01-07", + "/api/email_alerts?bbl=3012380016&indicator=complaints&start_date=2024-01-01&end_date=2024-01-07", + "/api/email_alerts?bbl=3012380016&indicator=eviction_filings&start_date=2024-01-01&end_date=2024-01-07", + ] + for url in urls: + res = client.get(url, **AUTH_ARG) + assert res.status_code == 200 + assert res.json()["result"] is not None + + def test_auth_works(self, db, client): + res = client.get( + "/api/email_alerts?bbl=3012380016&indicator=lagged_eviction_filings&prev_date=2024-01-07" + ) + assert res.status_code == 401 + + +class TestAlertsMultiIndicator(ApiTest): + HTTP_400_URLS = [ + "/api/email_alerts_multi", + "/api/email_alerts_multi?bbl=bop", + "/api/email_alerts_multi?bbl=3012380016&indicators=bop", + "/api/email_alerts_multi?bbl=3012380016&indicators=violations,lagged_eviction_filings&start_date=2024-01-01&end_date=2024-01-01", + "/api/email_alerts_multi?bbl=3012380016&indicators=violations,complaints&prev_date=2024-01-01", + ] + + def test_it_works(self, db, client): + urls = [ + "/api/email_alerts_multi?bbl=3012380016&indicators=lagged_eviction_filings&prev_date=2024-01-07", + "/api/email_alerts_multi?bbl=3012380016&indicators=violations&start_date=2024-01-01&end_date=2024-01-07", + "/api/email_alerts_multi?bbl=3012380016&indicators=complaints&start_date=2024-01-01&end_date=2024-01-07", + "/api/email_alerts_multi?bbl=3012380016&indicators=eviction_filings&start_date=2024-01-01&end_date=2024-01-07", + "/api/email_alerts_multi?bbl=3012380016&indicators=violations,complaints,eviction_filings&start_date=2024-01-01&end_date=2024-01-07", + "/api/email_alerts_multi?bbl=3012380016&indicators=violations,complaints,eviction_filings,lagged_eviction_filings&start_date=2024-01-01&end_date=2024-01-07&prev_date=2024-01-01", + ] + for url in urls: + res = client.get(url, **AUTH_ARG) + print(res.json()) + assert res.status_code == 200 + assert res.json()["result"] is not None + + def test_auth_works(self, db, client): + res = client.get( + "/api/email_alerts_multi?bbl=3012380016&indicator=lagged_eviction_filings&prev_date=2024-01-07" + ) + assert res.status_code == 401 + + class TestAddressExport(ApiTest): HTTP_400_URLS = [ "/api/address/export", diff --git a/wow/views.py b/wow/views.py index d3e1b86c1..cc47b0cc3 100644 --- a/wow/views.py +++ b/wow/views.py @@ -8,7 +8,14 @@ from .datautil import int_or_none, float_or_none from . import csvutil, apiutil from .apiutil import api, get_validated_form_data, authorize_for_alerts -from .forms import PaddedBBLForm, SeparatedBBLForm, EmailAlertForm +from .forms import ( + EmailAlertLaggedEvictionFilingsForm, + EmailAlertMultiIndicatorForm, + EmailAlertSingleIndicatorForm, + EmailAlertViolationsForm, + PaddedBBLForm, + SeparatedBBLForm, +) MY_DIR = Path(__file__).parent.resolve() @@ -188,10 +195,6 @@ def address_latestdeed(request): return JsonResponse({"result": list(result)}) -def get_alert_params_from_request(request) -> dict: - return get_validated_form_data(EmailAlertForm, request.GET) - - @api def alerts_violations(request): """ @@ -199,7 +202,7 @@ def alerts_violations(request): and end_date (yyyy-mm-dd), and responds with the number of HPD violations that the property recieved within that time period. """ - args = get_alert_params_from_request(request) + args = get_validated_form_data(EmailAlertViolationsForm, request.GET) query_params = { "bbl": args["bbl"], "start_date": args["start_date"], @@ -213,6 +216,7 @@ def alerts_violations(request): return JsonResponse({"result": list(result)}) +@api def email_alerts_lagged_eviction_filings(request): """ This API endpoint receives requests with a 10-digit BBL and prev_date @@ -221,7 +225,7 @@ def email_alerts_lagged_eviction_filings(request): have only appeared in the database after that date (ie. lagged filings). """ authorize_for_alerts(request) - args = get_alert_params_from_request(request) + args = get_validated_form_data(EmailAlertLaggedEvictionFilingsForm, request.GET) query_params = { "bbl": args["bbl"], "prev_date": args["prev_date"], @@ -240,6 +244,15 @@ def email_alerts_lagged_eviction_filings(request): } +def combine_alert_subqueries(indicators): + cte_subqueries = [f"{i} as ( {ALERTS_QUERIES[i].read_text()} )" for i in indicators] + return f""" + with {",".join(cte_subqueries)} + select * + from {','.join(indicators)} + """ + + @api def email_alerts(request): """ @@ -247,12 +260,14 @@ def email_alerts(request): and end_date (yyyy-mm-dd), and an indicator name. It responds with the value for that indicator for the property over the time period. """ - args = get_alert_params_from_request(request) + authorize_for_alerts(request) + args = get_validated_form_data(EmailAlertSingleIndicatorForm, request.GET) sql_file = ALERTS_QUERIES[args["indicator"]] query_params = { "bbl": args["bbl"], "start_date": args["start_date"], "end_date": args["end_date"], + "prev_date": args["prev_date"], } result = exec_db_query(sql_file, query_params) result[0].update(query_params) @@ -268,7 +283,7 @@ def email_alerts_multi(request): property over the time period. """ authorize_for_alerts(request) - args = get_alert_params_from_request(request) + args = get_validated_form_data(EmailAlertMultiIndicatorForm, request.GET) query_params = { "bbl": args["bbl"], "start_date": args["start_date"], @@ -281,15 +296,6 @@ def email_alerts_multi(request): return JsonResponse({"result": list(result)}) -def combine_alert_subqueries(indicators): - cte_subqueries = [f"{i} as ( {ALERTS_QUERIES[i].read_text()} )" for i in indicators] - return f""" - with {",".join(cte_subqueries)} - select * - from {','.join(indicators)} - """ - - def _fixup_addr_for_csv(addr: Dict[str, Any]): addr["ownernames"] = csvutil.stringify_owners(addr["ownernames"] or []) addr["recentcomplaintsbytype"] = csvutil.stringify_complaints( From 5e7bec9dc4316583f0e188beda8390dc59cfc6a5 Mon Sep 17 00:00:00 2001 From: Maxwell Austensen Date: Fri, 2 Feb 2024 18:10:47 -0500 Subject: [PATCH 2/3] black format --- wow/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wow/forms.py b/wow/forms.py index 5aa567637..292129b5c 100644 --- a/wow/forms.py +++ b/wow/forms.py @@ -122,7 +122,7 @@ def clean(self): data = self.cleaned_data indicators = data.get("indicators", []) start_end_indicators = ["violations", "complaints", "eviction_filings"] - + if "lagged_eviction_filings" in indicators: if not data.get("prev_date", None): raise forms.ValidationError( From 33431f2e8d7eaa709eabb106caef9536c2950fd9 Mon Sep 17 00:00:00 2001 From: Maxwell Austensen Date: Fri, 2 Feb 2024 18:23:17 -0500 Subject: [PATCH 3/3] break long lines --- wow/tests/test_views.py | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/wow/tests/test_views.py b/wow/tests/test_views.py index aaa62007f..a5b7ff68b 100644 --- a/wow/tests/test_views.py +++ b/wow/tests/test_views.py @@ -185,11 +185,12 @@ class TestAlertsSingleIndicator(ApiTest): ] def test_it_works(self, db, client): + url_bbl_base = "/api/email_alerts?bbl=3012380016" urls = [ - "/api/email_alerts?bbl=3012380016&indicator=lagged_eviction_filings&prev_date=2024-01-07", - "/api/email_alerts?bbl=3012380016&indicator=violations&start_date=2024-01-01&end_date=2024-01-07", - "/api/email_alerts?bbl=3012380016&indicator=complaints&start_date=2024-01-01&end_date=2024-01-07", - "/api/email_alerts?bbl=3012380016&indicator=eviction_filings&start_date=2024-01-01&end_date=2024-01-07", + f"{url_bbl_base}&indicator=lagged_eviction_filings&prev_date=2024-01-07", + f"{url_bbl_base}&indicator=violations&start_date=2024-01-01&end_date=2024-01-07", + f"{url_bbl_base}&indicator=complaints&start_date=2024-01-01&end_date=2024-01-07", + f"{url_bbl_base}&indicator=eviction_filings&start_date=2024-01-01&end_date=2024-01-07", ] for url in urls: res = client.get(url, **AUTH_ARG) @@ -198,7 +199,8 @@ def test_it_works(self, db, client): def test_auth_works(self, db, client): res = client.get( - "/api/email_alerts?bbl=3012380016&indicator=lagged_eviction_filings&prev_date=2024-01-07" + "/api/email_alerts?bbl=3012380016&indicator=lagged_eviction_filings \ + &prev_date=2024-01-07" ) assert res.status_code == 401 @@ -208,18 +210,26 @@ class TestAlertsMultiIndicator(ApiTest): "/api/email_alerts_multi", "/api/email_alerts_multi?bbl=bop", "/api/email_alerts_multi?bbl=3012380016&indicators=bop", - "/api/email_alerts_multi?bbl=3012380016&indicators=violations,lagged_eviction_filings&start_date=2024-01-01&end_date=2024-01-01", - "/api/email_alerts_multi?bbl=3012380016&indicators=violations,complaints&prev_date=2024-01-01", + "/api/email_alerts_multi?bbl=3012380016&indicators=violations,lagged_eviction_filings \ + &start_date=2024-01-01&end_date=2024-01-01", + "/api/email_alerts_multi?bbl=3012380016&indicators=violations,complaints \ + &prev_date=2024-01-01", ] def test_it_works(self, db, client): + url_bbl_base = "/api/email_alerts_multi?bbl=3012380016" + start_date = "start_date=2024-01-01" + end_date = "end_date=2024-01-07" urls = [ - "/api/email_alerts_multi?bbl=3012380016&indicators=lagged_eviction_filings&prev_date=2024-01-07", - "/api/email_alerts_multi?bbl=3012380016&indicators=violations&start_date=2024-01-01&end_date=2024-01-07", - "/api/email_alerts_multi?bbl=3012380016&indicators=complaints&start_date=2024-01-01&end_date=2024-01-07", - "/api/email_alerts_multi?bbl=3012380016&indicators=eviction_filings&start_date=2024-01-01&end_date=2024-01-07", - "/api/email_alerts_multi?bbl=3012380016&indicators=violations,complaints,eviction_filings&start_date=2024-01-01&end_date=2024-01-07", - "/api/email_alerts_multi?bbl=3012380016&indicators=violations,complaints,eviction_filings,lagged_eviction_filings&start_date=2024-01-01&end_date=2024-01-07&prev_date=2024-01-01", + f"{url_bbl_base}&indicators=lagged_eviction_filings&prev_date=2024-01-07", + f"{url_bbl_base}&indicators=violations&{start_date}&{end_date}", + f"{url_bbl_base}&indicators=complaints&{start_date}&{end_date}", + f"{url_bbl_base}&indicators=eviction_filings&{start_date}&{end_date}", + f"{url_bbl_base}&indicators=violations,complaints,eviction_filings \ + &{start_date}&{end_date}", + f"{url_bbl_base} \ + &indicators=violations,complaints,eviction_filings,lagged_eviction_filings \ + &{start_date}&{end_date}&prev_date=2024-01-01", ] for url in urls: res = client.get(url, **AUTH_ARG) @@ -229,7 +239,8 @@ def test_it_works(self, db, client): def test_auth_works(self, db, client): res = client.get( - "/api/email_alerts_multi?bbl=3012380016&indicator=lagged_eviction_filings&prev_date=2024-01-07" + "/api/email_alerts_multi?bbl=3012380016&indicator=lagged_eviction_filings \ + &prev_date=2024-01-07" ) assert res.status_code == 401