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

Mohit's Code Challenge #53

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
#
# Read more on Dockerfile best practices at the source:
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client nodejs
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-client nodejs npm

# Inside the container, create an app directory and switch into it
RUN mkdir /app
Expand Down
40 changes: 40 additions & 0 deletions parserator_web/static/js/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,42 @@
/* TODO: Flesh this out to connect the form to the API and render results
in the #address-results div. */
var api_url = "/api/parse";
var button = document.getElementById("submit");
var address = document.getElementById("address");
var parse_type = document.getElementById("parse-type")
button.addEventListener("click", function (event) {
event.preventDefault();
fetch(api_url + "?address=" + address.value).then(response => response.json())
.then(data => {
const table_body = document.getElementById("table_body")
table_body.innerHTML = '';
document.getElementById("address-results").style.display = "none";
const errors = document.getElementById('errors');
errors.style.display = "none"
if (data.errors) {
errors.innerText = data.errors;
errors.style.display = "block"
}
else {
let address_parts, address_type;
[address_parts, address_type] = data.payload;
parse_type.innerText = address_type
for (const key in address_parts) {
let r1 = document.createElement("tr")
let c1 = document.createElement("td")
c1.innerText = key
let c2 = document.createElement("td")
c2.innerText = address_parts[key]
r1.appendChild(c1);
r1.appendChild(c2);
table_body.appendChild(r1);
}

document.getElementById("address-results").style.display = "block";
}
})
.catch(error => {
console.error('Error', error);
});

});
184 changes: 91 additions & 93 deletions parserator_web/templates/parserator_web/base.html
Original file line number Diff line number Diff line change
@@ -1,98 +1,96 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>{% block title %}{% endblock %} | Parserator</title>

<meta content="Description TK" name="description" />
<meta content="Author TK" name="author" />

<!-- Facebook metadata -->
<meta property="og:site_name" content="Parserator">
<meta property="og:type" content="website">
<meta property="og:title" content="Title TK">
<meta property="og:description" content="Description TK">
<meta property="og:url" content="URL TK">
<meta property="og:image" content="Image TK">

<!-- Twitter metadata -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="Parserator">
<meta name="twitter:creator" content="Creator TK">
<meta name="twitter:title" content="Title TK">
<meta name="twitter:url" content="URL TK">
<meta name="twitter:description" content="Description TK">
<meta name="twitter:image" content="Image TK">

<!-- Override this block to add extra meta tags -->
{% block extra_meta %}{% endblock %}

<link rel="shortcut icon" type="image/ico" href="{% static 'images/favicon.ico' %}"/>
<link rel="shortcut icon" type="image/ico" href="{% static 'images/favicon-16x16.png' %}" sizes="16x16" />
<link rel="shortcut icon" type="image/ico" href="{% static 'images/favicon-32x32.png' %}" sizes="32x32" />

<!-- Bootstrap core CSS -->
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'css/custom.css' %}" rel="stylesheet">

<!-- Load fonts, if necessary -->
<!-- link href="https://fonts.googleapis.com/css?family=Roboto+Slab|Open+Sans:400,700&display=swap" rel="stylesheet" -->

<!-- Override this block to add extra stylesheets -->
{% block extra_css %}{% endblock %}
</head>

<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark pl-2 pl-md-4">
<div class="justify-content-left va-container">
{% block navbar_brand %}
<a class="navbar-brand" href="/">
<div id="navbar-title" class="d-inline-block">
<span class="d-none d-sm-inline navbar-title-text">
Parserator
</span>
</div>
</a>
{% endblock %}
</div>
</nav>

<div id="main-body">
<div class="mt-3 mt-lg-5 pb-5 mb-5">
{% block body %}{% endblock %}
</div>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>{% block title %}{% endblock %} | Parserator</title>

<meta content="Description TK" name="description" />
<meta content="Author TK" name="author" />

<!-- Facebook metadata -->
<meta property="og:site_name" content="Parserator">
<meta property="og:type" content="website">
<meta property="og:title" content="Title TK">
<meta property="og:description" content="Description TK">
<meta property="og:url" content="URL TK">
<meta property="og:image" content="Image TK">

<!-- Twitter metadata -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="Parserator">
<meta name="twitter:creator" content="Creator TK">
<meta name="twitter:title" content="Title TK">
<meta name="twitter:url" content="URL TK">
<meta name="twitter:description" content="Description TK">
<meta name="twitter:image" content="Image TK">

<!-- Override this block to add extra meta tags -->
{% block extra_meta %}{% endblock %}

<link rel="shortcut icon" type="image/ico" href="{% static 'images/favicon.ico' %}" />
<link rel="shortcut icon" type="image/ico" href="{% static 'images/favicon-16x16.png' %}" sizes="16x16" />
<link rel="shortcut icon" type="image/ico" href="{% static 'images/favicon-32x32.png' %}" sizes="32x32" />

<!-- Bootstrap core CSS -->
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'css/custom.css' %}" rel="stylesheet">

<!-- Load fonts, if necessary -->
<!-- link href="https://fonts.googleapis.com/css?family=Roboto+Slab|Open+Sans:400,700&display=swap" rel="stylesheet" -->

<!-- Override this block to add extra stylesheets -->
{% block extra_css %}{% endblock %}
</head>

<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark pl-2 pl-md-4">
<div class="justify-content-left va-container">
{% block navbar_brand %}
<a class="navbar-brand" href="/">
<div id="navbar-title" class="d-inline-block">
<span class="d-none d-sm-inline navbar-title-text">
Parserator
</span>
</div>
</a>
{% endblock %}
</div>
</nav>

<div id="main-body">
<div class="mt-3 mt-lg-5 pb-5 mb-5">
{% block body %}{% endblock %}
</div>
</div>

<footer class="footer bg-dark text-light pt-5 pb-3">
<div class="container-fluid text-center">
<h3 class="mb-1">
Parserator
</h3>
<p class="mt-3">
Website by <br />
<a href="https://datamade.us">
<img class="mb-4 mt-2" style="height:20px" src="{% static 'images/datamade-logo.png' %}" alt="DataMade" />
</a>
<br>
... and Mohit!
</p>
</div>
</footer>

<!-- Load external scripts -->
<script src="{% static 'js/lib/jquery.min.js' %}"></script>
<script src="{% static 'js/lib/bootstrap.bundle.min.js' %}"></script>
<script src="{% static 'js/lib/fontawesome.min.js' %}"></script>
<script src="{% static 'js/lib/solid.min.js' %}"></script>

<!-- Load extra scripts -->
{% block extra_js %}{% endblock %}
</body>

<footer class="footer bg-dark text-light pt-5 pb-3">
<div class="container-fluid text-center">
<h3 class="mb-1">
Parserator
</h3>
<p class="mt-3">
Website by <br/>
<a href="https://datamade.us">
<img
class="mb-4 mt-2" style="height:20px"
src="{% static 'images/datamade-logo.png' %}"
alt="DataMade"
/>
</a>
<br>
... and you!
</p>
</div>
</footer>

<!-- Load external scripts -->
<script src="{% static 'js/lib/jquery.min.js' %}"></script>
<script src="{% static 'js/lib/bootstrap.bundle.min.js' %}"></script>
<script src="{% static 'js/lib/fontawesome.min.js' %}"></script>
<script src="{% static 'js/lib/solid.min.js' %}"></script>

<!-- Load extra scripts -->
{% block extra_js %}{% endblock %}
</body>
</html>
</html>
17 changes: 12 additions & 5 deletions parserator_web/templates/parserator_web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@
<h3 id="usaddress-parser"><i class="fa fa-fw fa-map-marker-alt"></i> U.S. address parser</h3>
<p>Dealing with some messy or unstructured addresses? We can parse them for you.</p>
<div class="card card-body bg-light">
<p><strong>Try it out!</strong> Parse an address in the United States into fields like <code>AddressNumber</code>, <code>StreetName</code> and <code>ZipCode</code>.</p>
<p><strong>Try it out!</strong> Parse an address in the United States into fields like
<code>AddressNumber</code>, <code>StreetName</code> and <code>ZipCode</code>.
</p>
<form class="form" role="form">
{% csrf_token %}
<input name="address" type="text" class="form-control" id="address" placeholder="123 Main St. Suite 100 Chicago, IL">
<input name="address" type="text" class="form-control" id="address"
placeholder="123 Main St. Suite 100 Chicago, IL">
<button id="submit" type="submit" class="btn btn-success mt-3">Parse!</button>
</form>
</div>
<!-- Error Handling -->
<div id="errors" class="alert alert-danger" style="display: none;">

</div>
<!-- TODO: Display parsed address components here. -->
<div id="address-results" style="display:none">
Expand All @@ -28,7 +35,7 @@ <h4>Parsing results</h4>
<th>Tag</th>
</tr>
</thead>
<tbody>
<tbody id="table_body">
</tbody>
</table>
</div>
Expand All @@ -38,5 +45,5 @@ <h4>Parsing results</h4>
{% endblock %}

{% block extra_js %}
<script src="{% static 'js/index.js' %}"></script>
{% endblock %}
<script src="{% static 'js/index.js' %}"></script>
{% endblock %}
16 changes: 14 additions & 2 deletions parserator_web/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer
from rest_framework.exceptions import ParseError


class Home(TemplateView):
Expand All @@ -16,9 +15,22 @@ class AddressParse(APIView):
def get(self, request):
# TODO: Flesh out this method to parse an address string using the
# parse() method and return the parsed components to the frontend.
return Response({})
request_params = request.query_params
d = {'payload': '', 'errors': ''}
try:
if 'address' in request_params:
try:
d['payload'] = self.parse(request_params['address'])
except usaddress.RepeatedLabelError:
d['errors'] = 'Repeated Labels'
except ValueError:
d['errors'] = 'Fill a valid address'
return Response(d)

def parse(self, address):
# TODO: Implement this method to return the parsed components of a
# given address using usaddress: https://github.com/datamade/usaddress
if address == "":
raise ValueError("Parse again")
(address_components, address_type) = usaddress.tag(address)
return address_components, address_type
26 changes: 24 additions & 2 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,33 @@ def test_api_parse_succeeds(client):
# TODO: Finish this test. Send a request to the API and confirm that the
# data comes back in the appropriate format.
address_string = '123 main st chicago il'
pytest.fail()
response = client.get("/api/parse", {"address": address_string}, follow=True)
expected_answer = {"payload": [
{
"AddressNumber": "123",
"StreetName": "main",
"StreetNamePostType": "st",
"PlaceName": "chicago",
"StateName": "il"
},
"Street Address"
],
"errors": ""
}
if response.json()['errors'] != '':
pytest.fail()
assert response.json()['payload'] == expected_answer['payload']


def test_api_parse_raises_error(client):
# TODO: Finish this test. The address_string below will raise a
# RepeatedLabelError, so ParseAddress.parse() will not be able to parse it.
address_string = '123 main st chicago il 123 main st'
pytest.fail()
response = client.get("/api/parse", {"address": address_string}, follow=True)
expected_answer = {
"payload": "",
"errors": "Repeated Labels"
}
if response.json()['errors'] == '':
pytest.fail()
assert response.json()['errors'] == expected_answer['errors']