import bottle import datetime from . import database, parcelsapp PARCELSAPP_CLIENT: parcelsapp.ParcelsAppClient | None = None TEMPLATE = """ <doctype HTML> <html> <head> <style type="text/css"> .tracking-grid { display: grid; grid-template-columns: 1fr; grid-gap: 10px; } .tracking-item { display: grid; grid-template-columns: 150px 1fr auto; grid-gap: 0.5em; 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; } .tracking-item.unknown { background: red; } h1 { text-align: center; } main { max-width: 800px; margin:auto; } body { font-family: sans; } a { color:black; } .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; } footer { margin-top: 10em; } </style> </head> <body> % if with_form: <h1>Parcels</h1> % end <main> % if error_message is not None: <div class="error-message">{{error_message}}</div> % end <div class="tracking-grid"> % for entry, tracking_data in tracking_results: <a target="_blank" href="{{tracking_data.tracking_url if tracking_data else ''}}"> <div class="tracking-item {{tracking_data.status if tracking_data else 'unknown'}}"> <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 if tracking_data else 'unknown' }}</div> <div class="tracking-update-date">{{ tracking_data.latest_state().date.date() if tracking_data else '???' }}</div> </div> </a> % end % if len(tracking_results) == 0: <div style="text-align: center"><b>No Parcels yet...<br>Add some below!</b></div> % end </div> </main> % if with_form: <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> % end </body> </html> """ TODAY = datetime.datetime.now(tz=datetime.UTC).date() def get_packages_from_parcels(): tracking_entries = database.get_tracking_numbers() tracking_numbers = [e.number for e in tracking_entries] try: tracking_results = list(PARCELSAPP_CLIENT.get_tracking_status(tracking_numbers)) error_message = None except parcelsapp.ParcelsApiError as ex: tracking_results = [] error_message = str(ex) tracking_results_by_id = { result.tracking_number: result for result in tracking_results } return [(e, tracking_results_by_id.get(e.number)) for e in tracking_entries] def render_tracking(tracking_results_with_name, error_message: str | None, with_form: bool): tracking_results_with_name = get_packages_from_parcels() tracking_results_with_name.sort(key=lambda x: x[1].latest_state().date if x[1] else TODAY, reverse=True) return bottle.template(TEMPLATE, error_message=error_message, 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) @bottle.route('/add', method='POST') def add_tracking_number(): 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())) return bottle.redirect('/') def initialize_server(parcelsapp_client: parcelsapp.ParcelsAppClient): global PARCELSAPP_CLIENT PARCELSAPP_CLIENT = parcelsapp_client bottle.run(host='0.0.0.0', port=8080, debug=False)