2025-01-22 17:19:05 +00:00
|
|
|
import bottle
|
2025-01-22 16:31:00 +00:00
|
|
|
|
|
|
|
from . import database, parcelsapp
|
2025-01-22 13:02:02 +00:00
|
|
|
|
|
|
|
PARCELSAPP_CLIENT: parcelsapp.ParcelsAppClient | None = None
|
|
|
|
|
2025-01-22 16:31:00 +00:00
|
|
|
TEMPLATE = """
|
2025-01-22 14:58:55 +00:00
|
|
|
<doctype HTML>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<style type="text/css">
|
|
|
|
|
2025-01-22 15:50:00 +00:00
|
|
|
.tracking-grid {
|
|
|
|
display: grid;
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
grid-gap: 10px;
|
|
|
|
}
|
2025-01-22 14:58:55 +00:00
|
|
|
|
2025-01-22 15:50:00 +00:00
|
|
|
.tracking-item {
|
|
|
|
display: grid;
|
|
|
|
grid-template-columns: 150px 1fr auto;
|
2025-01-22 21:39:34 +00:00
|
|
|
grid-gap: 0.5em;
|
2025-01-22 15:50:00 +00:00
|
|
|
padding: 0.5em 0.2em;
|
|
|
|
border-radius: 5px;
|
|
|
|
border: black solid 1px;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tracking-name {
|
|
|
|
grid-column: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tracking-name-inner {
|
|
|
|
border: solid black 1px;
|
|
|
|
padding: 0.2em;
|
|
|
|
border-radius: 3px;
|
|
|
|
background-color: #FFF8;
|
|
|
|
}
|
|
|
|
|
|
|
|
a {
|
|
|
|
text-decoration: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tracking-status {
|
|
|
|
grid-column: 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tracking-update-date {
|
|
|
|
grid-column: 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tracking-item.delivered {
|
|
|
|
background: #ABFBD6;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tracking-item.transit {
|
|
|
|
background: #AEABFB;
|
|
|
|
}
|
|
|
|
|
|
|
|
h1 {
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
main {
|
|
|
|
max-width: 800px;
|
|
|
|
margin:auto;
|
|
|
|
}
|
|
|
|
|
|
|
|
body {
|
|
|
|
font-family: sans;
|
|
|
|
}
|
|
|
|
|
|
|
|
a {
|
|
|
|
color:black;
|
|
|
|
}
|
2025-01-22 17:19:05 +00:00
|
|
|
|
|
|
|
.add-number-form {
|
|
|
|
display: grid;
|
|
|
|
grid-template: auto 1fr;
|
|
|
|
max-width: 300px;
|
|
|
|
grid-gap: 2px;
|
|
|
|
margin: auto;
|
|
|
|
}
|
|
|
|
|
|
|
|
.add-number-form .add {
|
|
|
|
grid-column: 1 / 3;
|
|
|
|
}
|
2025-01-22 17:23:55 +00:00
|
|
|
|
|
|
|
footer {
|
|
|
|
margin-top: 10em;
|
|
|
|
}
|
2025-01-22 14:58:55 +00:00
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
|
2025-01-22 20:21:17 +00:00
|
|
|
% if with_form:
|
2025-01-22 15:50:00 +00:00
|
|
|
<h1>Parcels</h1>
|
2025-01-22 20:21:17 +00:00
|
|
|
% end
|
2025-01-22 14:58:55 +00:00
|
|
|
|
|
|
|
<main>
|
|
|
|
|
|
|
|
<div class="tracking-grid">
|
|
|
|
% for entry, tracking_data in tracking_results:
|
2025-01-22 21:39:34 +00:00
|
|
|
<a target="_blank" href="{{tracking_data.tracking_url}}">
|
2025-01-22 15:50:00 +00:00
|
|
|
<div class="tracking-item {{tracking_data.status}}">
|
|
|
|
<div class="tracking-name" title="{{entry.number}}"><span class="tracking-name-inner">{{ entry.name }}</span></div>
|
|
|
|
<div class="tracking-status">{{ tracking_data.latest_state().status }}</div>
|
|
|
|
<div class="tracking-update-date">{{ tracking_data.latest_state().date.date() }}</div>
|
|
|
|
</div>
|
|
|
|
</a>
|
2025-01-22 14:58:55 +00:00
|
|
|
% end
|
2025-01-22 20:20:16 +00:00
|
|
|
% if len(tracking_results) == 0:
|
|
|
|
<div style="text-align: center"><b>No Parcels yet...<br>Add some below!</b></div>
|
|
|
|
% end
|
2025-01-22 14:58:55 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
</main>
|
|
|
|
|
2025-01-22 17:23:55 +00:00
|
|
|
% if with_form:
|
2025-01-22 17:19:05 +00:00
|
|
|
<footer>
|
|
|
|
<form action="/add" method="POST" class="add-number-form">
|
|
|
|
<label for="name">Name</label>
|
|
|
|
<input type="text" name="name" id="name" required />
|
|
|
|
<label for="tracking-number">Number</label>
|
|
|
|
<input type="text" name="tracking-number" id="tracking-number" required />
|
|
|
|
<input class="add" type="submit" value="Add Tracking Number!" />
|
|
|
|
</form>
|
|
|
|
</footer>
|
2025-01-22 17:23:55 +00:00
|
|
|
% end
|
2025-01-22 17:19:05 +00:00
|
|
|
|
2025-01-22 14:58:55 +00:00
|
|
|
</body>
|
|
|
|
</html>
|
2025-01-22 16:31:00 +00:00
|
|
|
"""
|
|
|
|
|
2025-01-22 13:02:02 +00:00
|
|
|
|
2025-01-22 17:23:55 +00:00
|
|
|
def render_tracking(with_form: bool):
|
2025-01-22 14:58:55 +00:00
|
|
|
tracking_entries = database.get_tracking_numbers()
|
|
|
|
tracking_numbers = [e.number for e in tracking_entries]
|
|
|
|
|
|
|
|
tracking_results = PARCELSAPP_CLIENT.get_tracking_status(tracking_numbers)
|
|
|
|
|
2025-01-22 16:31:00 +00:00
|
|
|
tracking_results_by_id = {
|
|
|
|
result.tracking_number: result for result in tracking_results
|
|
|
|
}
|
2025-01-22 14:58:55 +00:00
|
|
|
|
2025-01-22 17:19:05 +00:00
|
|
|
tracking_results_with_name = [(e, tracking_results_by_id.get(e.number)) for e in tracking_entries]
|
|
|
|
tracking_results_with_name.sort(key=lambda x: x[1].latest_state().date, reverse=True)
|
|
|
|
|
2025-01-22 17:23:55 +00:00
|
|
|
return bottle.template(TEMPLATE, tracking_results=tracking_results_with_name, with_form=with_form)
|
|
|
|
|
|
|
|
@bottle.route('/')
|
|
|
|
def index():
|
|
|
|
return render_tracking(with_form=True)
|
|
|
|
|
|
|
|
@bottle.route('/noninteraction')
|
|
|
|
def inner():
|
|
|
|
return render_tracking(with_form=False)
|
2025-01-22 17:19:05 +00:00
|
|
|
|
2025-01-22 13:02:02 +00:00
|
|
|
|
2025-01-22 17:19:05 +00:00
|
|
|
@bottle.route('/add', method='POST')
|
2025-01-22 20:54:40 +00:00
|
|
|
def add_tracking_number():
|
2025-01-25 23:27:55 +00:00
|
|
|
number: str = bottle.request.forms.get('tracking-number')
|
|
|
|
name: str = bottle.request.forms.get('name')
|
|
|
|
if number is None or name is None:
|
|
|
|
bottle.abort(400)
|
|
|
|
database.add_tracking_number(database.TrackingNumberEntry(number.strip(), name.strip()))
|
2025-01-22 17:19:05 +00:00
|
|
|
return bottle.redirect('/')
|
2025-01-22 13:02:02 +00:00
|
|
|
|
2025-01-22 16:31:00 +00:00
|
|
|
|
2025-01-22 13:02:02 +00:00
|
|
|
def initialize_server(parcelsapp_client: parcelsapp.ParcelsAppClient):
|
|
|
|
global PARCELSAPP_CLIENT
|
|
|
|
PARCELSAPP_CLIENT = parcelsapp_client
|
2025-01-22 20:44:21 +00:00
|
|
|
bottle.run(host='0.0.0.0', port=8080, debug=False)
|