diff --git a/server/api.py b/server/api.py index d2e782a..b65e298 100644 --- a/server/api.py +++ b/server/api.py @@ -79,6 +79,15 @@ class API: d.set_stop(request.forms.get('stop_id')) return {'success': True} + @route('/admin/devices/change_filter', method='POST') + def admin_devices_change_filter(): + if main.config["admin"]["secret"] != request.forms.get('secret'): + return {'error': "unauthorized"} + for i, d in enumerate(main.controller.devices): + if str(i) == request.forms.get('index'): + d.set_filter(request.forms.get('filter')) + return {'success': True} + @route('/admin/devices/toggle', method='POST') def admin_devices_toggle(): if main.config["admin"]["secret"] != request.forms.get('secret'): diff --git a/server/departures.py b/server/departures.py index 4e8a224..55efb40 100644 --- a/server/departures.py +++ b/server/departures.py @@ -2,6 +2,38 @@ from math import floor from datetime import datetime from dateutil import parser +class Filter: + + storage = dict() + + @staticmethod + def get(name: str): + if name in Filter.storage: + return Filter.storage[name] + return None + + def __init__(self, name: str, filters): + if "lines" not in filters: + filters["lines"] = None + if "types" not in filters: + filters["types"] = None + if "destinations" not in filters: + filters["destinations"] = None + self.name = name + self.lines = filters["lines"] + self.types = filters["types"] + self.destinations = filters["destinations"] + Filter.storage[name] = self + + def filter(self, departures): + results = [] + for d in departures: + if not self.types or d.type in self.types: + if not self.lines or d.line in self.lines: + if not self.destinations or d.last_stop in self.destinations: + results.append(d) + return results + class Departure: id_pool = {} diff --git a/server/lora.py b/server/lora.py index 5fee812..c1fe810 100644 --- a/server/lora.py +++ b/server/lora.py @@ -7,7 +7,7 @@ from base64 import b64encode from datetime import datetime from random import randint, shuffle from time import sleep -from departures import Departure +from departures import Departure, Filter import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) @@ -34,22 +34,23 @@ class LoraController: data = requests.post(url, verify=False, headers=headers, data=json.dumps(data)).json() self.token = data["token"] - def new(self, id: int, stop_id: str, enabled: bool): - self.devices.append(LoraDevice(self, id, stop_id, enabled)) + def new(self, id: int, stop_id: str, enabled: bool, filter: Filter): + self.devices.append(LoraDevice(self, id, stop_id, enabled, filter)) def json(self): resp = [] for d in self.devices: - resp.append({'id': f"{d.id:0>16x}", 'stop_id': d.stop_id, 'enabled': d.enabled}) + resp.append({'id': f"{d.id:0>16x}", 'stop_id': d.stop_id, 'enabled': d.enabled, 'filter': d.filter.name if d.filter else None}) return resp class LoraDevice: - def __init__(self, controller: LoraController, deveui: int, stop_id: str, enabled: bool): + def __init__(self, controller: LoraController, deveui: int, stop_id: str, enabled: bool, filter: Filter): self.controller = controller self.id = deveui self.stop_id = stop_id self.enabled = enabled + self.filter = filter self.message_pool = [] self.thread = None self.port = 1 @@ -59,11 +60,17 @@ class LoraDevice: self.clear() self.stop_id = stop_id + def set_filter(self, name: str): + self.filter = Filter.get(name) + def get_updated_departures(self): if not self.enabled: return self.send_time() - for d in Departure.get(self.stop_id): + departures = Departure.get(self.stop_id) + if self.filter: + departures = self.filter.filter(departures) + for d in departures: if self.id not in d.updated or d.updated[self.id] > 0: self.send(d.data) diff --git a/server/main.py b/server/main.py index de76f43..edad577 100644 --- a/server/main.py +++ b/server/main.py @@ -1,4 +1,4 @@ -from departures import Departure +from departures import Departure, Filter from requests.structures import CaseInsensitiveDict import json import requests @@ -24,11 +24,15 @@ class Main: self.controller = lora_controller self.api = API(self) lora_controller.generate_token() + for name in self.config["filters"]: + Filter(name, self.config["filters"][name]) for d in self.config["devices"]: if "stop_id" in d: if "enabled" not in d: d["enabled"] = True - lora_controller.new(d["id"], str(d["stop_id"]), d["enabled"]) + if "filter" not in d: + d["filter"] = None + lora_controller.new(d["id"], str(d["stop_id"]), d["enabled"], Filter.get(d["filter"])) self.thread = threading.Thread(target=self.update_loop) self.thread.start() diff --git a/server/static/admin.css b/server/static/admin.css index aaa2a97..3326b14 100644 --- a/server/static/admin.css +++ b/server/static/admin.css @@ -3,11 +3,13 @@ .cards .header {padding: 15px; display: grid; grid-template-columns: 1fr max-content; user-select: none;} .cards .first {font-weight: 700;} -.cards .settings {padding: 15px; border-top: 1px solid var(--border-color2); background: var(--alt-bg2); display: none;} -.cards .settings.visible {display: block;} +.cards .settings {padding: 15px; border-top: 1px solid var(--border-color2); background: var(--alt-bg2); display: none; flex-direction: column; gap: 13px;} +.cards .settings.visible {display: flex;} .cards .actions {display: flex; gap: 10px; flex-wrap: wrap; align-items: center;} -.cards .actions::before {content: "Akce:"; font-weight: 500; font-size: 90%; opacity: .5; text-transform: uppercase;} +.cards .actions::before, .cards .filter::before {content: "Akce:"; font-weight: 500; font-size: 90%; opacity: .5; text-transform: uppercase;} +.cards .filter::before {content: "Aktivní filtr:"; margin-right: 10px;} + @media screen and (max-width: 500px) { .cards .actions::before {display: none;} } diff --git a/server/static/admin.html b/server/static/admin.html index ee8dc63..ecb08cb 100644 --- a/server/static/admin.html +++ b/server/static/admin.html @@ -18,12 +18,14 @@
{{ stops[d.stop_id] ? stops[d.stop_id].name : "Nenastaveno" }}
+
{{ d.filter ? d.filter : "žádný" }}
- - + + +
diff --git a/server/static/admin.js b/server/static/admin.js index 2c06b14..1f54573 100644 --- a/server/static/admin.js +++ b/server/static/admin.js @@ -3,10 +3,8 @@ const { createApp } = Vue; let app = createApp({ data() { return { - // logged: false, - // secret: "", - logged: true, - secret: "TajneHeslo", + logged: false, + secret: "", stops: {}, devices: [] } @@ -14,11 +12,11 @@ let app = createApp({ methods: { async update() { let devices = await api("/admin/devices", {secret: this.secret}); - let stops = await api("/stops"); if(devices.error) { alert("Neplatné heslo!"); return; } + let stops = await api("/stops"); this.devices = devices.devices; this.stops = stops.stops; this.logged = true; @@ -38,6 +36,12 @@ let app = createApp({ if(!stop_id || stop_id.trim() == "") return; this.devices[index].stop_id = stop_id; await api("/admin/devices/change_stop", {index, stop_id, secret: this.secret}); + }, + async device_change_filter(index) { + let filter = prompt("Zadejte jméno filtru:"); + if(!filter || filter.trim() == "") return; + this.devices[index].filter = filter; + await api("/admin/devices/change_filter", {index, filter, secret: this.secret}); } } }).mount('#app'); @@ -63,5 +67,4 @@ async function api(url, data) { } xhr.send(str.join("&")); }); -} -app.update(); \ No newline at end of file +} \ No newline at end of file