diff --git a/loadproduction.old.sh b/loadproduction.old.sh new file mode 100755 index 00000000..880622ca --- /dev/null +++ b/loadproduction.old.sh @@ -0,0 +1,5 @@ +#!/bin/sh +export C3NAV_CONFIG=/home/laura/Projekte/c3nav/data/c3nav.cfg +ssh root@34c3.c3nav.de "c3nav-manage 34c3 dumpdata mapdata --format json | gzip" | gunzip > production.json +python src/manage.py loaddata --app mapdata production.json +# rm production.json diff --git a/src/c3nav/control/forms.py b/src/c3nav/control/forms.py index c43f92ee..1b3a87f3 100644 --- a/src/c3nav/control/forms.py +++ b/src/c3nav/control/forms.py @@ -9,8 +9,8 @@ from itertools import chain import pytz from django.contrib.auth.models import User from django.db.models import Prefetch -from django.forms import ChoiceField, Form, IntegerField, ModelForm, Select, MultipleChoiceField, \ - ModelMultipleChoiceField +from django.forms import (ChoiceField, Form, IntegerField, ModelForm, ModelMultipleChoiceField, MultipleChoiceField, + Select) from django.utils import timezone from django.utils.translation import gettext_lazy as _ from django.utils.translation import ngettext_lazy diff --git a/src/c3nav/control/templates/control/base.html b/src/c3nav/control/templates/control/base.html index 207aa46c..862ae459 100644 --- a/src/c3nav/control/templates/control/base.html +++ b/src/c3nav/control/templates/control/base.html @@ -24,7 +24,7 @@ {% if request.user_permissions.manage_map_updates %} {% trans 'Map Updates' %} · {% endif %} - {% trans 'Mesh' %} · + {% trans 'Mesh' %} · {{ request.user.username }}

diff --git a/src/c3nav/control/templates/control/mesh_message_sending.html b/src/c3nav/control/templates/control/mesh_message_sending.html index 1e5cefb6..f12a2b6e 100644 --- a/src/c3nav/control/templates/control/mesh_message_sending.html +++ b/src/c3nav/control/templates/control/mesh_message_sending.html @@ -10,7 +10,7 @@ {% block subcontent %}

Go back

{% if msg_type == "MESH_ROUTE_REQUEST" %} -

Route to {{ msg_data.address }} {% if node_name %} ({{ node_name }}){% endif %}

+

Route to {{ msg_data.address }} {% if node_name %} ({{ node_name }}){% endif %}

{% endif %}
@@ -23,7 +23,7 @@ {% for address, name in recipients %} - {% if address != "ff:ff:ff:ff:ff:ff" %}{% endif %} + {% if address != "ff:ff:ff:ff:ff:ff" %}{% endif %} {{ address }}{% if name %} ({{ name }}){% endif %} {% if address != "ff:ff:ff:ff:ff:ff" %}{% endif %} diff --git a/src/c3nav/control/templates/control/mesh_messages.html b/src/c3nav/control/templates/control/mesh_messages.html index 4a70ad2c..7741b88b 100644 --- a/src/c3nav/control/templates/control/mesh_messages.html +++ b/src/c3nav/control/templates/control/mesh_messages.html @@ -31,7 +31,7 @@ {% for msg in mesh_messages %} {{ msg.datetime.date }} {{ msg.datetime.time|date:"H:i:s" }} - {{ msg.src_node }} + {{ msg.src_node }} {{ msg.get_message_type_display }} {% if msg.get_message_type_display == "CONFIG_FIRMWARE" %} @@ -76,7 +76,7 @@ {% endfor %} {% endif %} - {{ msg.uplink_node }} + {{ msg.uplink_node }} {% endfor %} diff --git a/src/c3nav/control/templates/control/mesh_node_detail.html b/src/c3nav/control/templates/control/mesh_node_detail.html index 5213e628..82e441e0 100644 --- a/src/c3nav/control/templates/control/mesh_node_detail.html +++ b/src/c3nav/control/templates/control/mesh_node_detail.html @@ -12,7 +12,7 @@ Name: {% if node.name %}{{ node.name }}{% else %}{% trans '(no name)' %}{% endif %}

- Uplink: {{ node.uplink }}
+ Uplink: {{ node.uplink }}
Last signin: {{ node.last_signin.date }} {{ node.last_signin.time|date:"H:i:s" }} @@ -29,10 +29,10 @@

- + {% trans 'Edit' %} - + {% trans 'View messages' %}

@@ -61,7 +61,7 @@ SSL: {{ node.last_messages.CONFIG_UPLINK.parsed.ssl }}

- + {% trans 'Change' %}

@@ -71,7 +71,7 @@ X={{ node.last_messages.CONFIG_POSITION.parsed.x_pos }}, Y={{ node.last_messages.CONFIG_POSITION.parsed.y_pos }}, Z={{ node.last_messages.CONFIG_POSITION.parsed.z_pos }}

- + {% trans 'Change' %}

@@ -81,7 +81,7 @@ {{ node.last_messages.CONFIG_LED.parsed.led_config }}

- + {% trans 'Change' %}

diff --git a/src/c3nav/control/templates/control/mesh_nodes.html b/src/c3nav/control/templates/control/mesh_nodes.html index 6202244c..981cdfa9 100644 --- a/src/c3nav/control/templates/control/mesh_nodes.html +++ b/src/c3nav/control/templates/control/mesh_nodes.html @@ -7,7 +7,7 @@

View messages

- + {% trans 'View received messages' %}
@@ -26,7 +26,7 @@

Logs

- + {% trans 'View log' %}
@@ -43,7 +43,7 @@ {% for node in nodes %} - {{ node }} + {{ node }} {{ node.last_messages.CONFIG_FIRMWARE.parsed.get_chip_display }} rev{{ node.last_messages.CONFIG_FIRMWARE.parsed.revision_major }}.{{ node.last_messages.CONFIG_FIRMWARE.parsed.revision_minor }} @@ -62,7 +62,7 @@ {{ timesince }} ago {% endblocktrans %} - {{ node.uplink }} + {{ node.uplink }} {% endfor %} diff --git a/src/c3nav/control/urls.py b/src/c3nav/control/urls.py index 8395db22..af535c15 100644 --- a/src/c3nav/control/urls.py +++ b/src/c3nav/control/urls.py @@ -1,12 +1,12 @@ from django.urls import path -from c3nav.control.views.mesh import MeshNodeListView, MeshMessageListView, MeshNodeDetailView, MeshMessageSendView, \ - MeshNodeEditView, MeshLogView, MeshMessageSendingView -from c3nav.control.views.mapupdates import map_updates -from c3nav.control.views.announcements import announcement_list, announcement_detail from c3nav.control.views.access import grant_access, grant_access_qr -from c3nav.control.views.users import UserListView, user_detail +from c3nav.control.views.announcements import announcement_detail, announcement_list from c3nav.control.views.base import ControlPanelIndexView +from c3nav.control.views.mapupdates import map_updates +from c3nav.control.views.mesh import (MeshLogView, MeshMessageListView, MeshMessageSendingView, MeshMessageSendView, + MeshNodeDetailView, MeshNodeEditView, MeshNodeListView) +from c3nav.control.views.users import UserListView, user_detail urlpatterns = [ path('users/', UserListView.as_view(), name='control.users'), @@ -16,13 +16,13 @@ urlpatterns = [ path('announcements/', announcement_list, name='control.announcements'), path('announcements//', announcement_detail, name='control.announcements.detail'), path('mapupdates/', map_updates, name='control.map_updates'), - path('mesh/', MeshNodeListView.as_view(), name='control.mesh_nodes'), - path('mesh/logs/', MeshLogView.as_view(), name='control.mesh_log'), - path('mesh/messages/', MeshMessageListView.as_view(), name='control.mesh_messages'), - path('mesh//', MeshNodeDetailView.as_view(), name='control.mesh_node.detail'), - path('mesh//edit/', MeshNodeEditView.as_view(), name='control.mesh_node.edit'), - path('mesh/message/sending//', MeshMessageSendingView.as_view(), name='control.mesh_message.sending'), - path('mesh/message///', MeshMessageSendView.as_view(), name='control.mesh_message.send'), - path('mesh/message//', MeshMessageSendView.as_view(), name='control.mesh_message.send'), + path('mesh/', MeshNodeListView.as_view(), name='control.mesh.nodes'), + path('mesh/logs/', MeshLogView.as_view(), name='control.mesh.log'), + path('mesh/messages/', MeshMessageListView.as_view(), name='control.mesh.messages'), + path('mesh//', MeshNodeDetailView.as_view(), name='control.mesh.node.detail'), + path('mesh//edit/', MeshNodeEditView.as_view(), name='control.mesh.node.edit'), + path('mesh/message/sending//', MeshMessageSendingView.as_view(), name='control.mesh.sending'), + path('mesh/message///', MeshMessageSendView.as_view(), name='control.mesh.send'), + path('mesh/message//', MeshMessageSendView.as_view(), name='control.mesh.send'), path('', ControlPanelIndexView.as_view(), name='control.index'), ] diff --git a/src/c3nav/control/views/announcements.py b/src/c3nav/control/views/announcements.py index b202b2b8..714862e3 100644 --- a/src/c3nav/control/views/announcements.py +++ b/src/c3nav/control/views/announcements.py @@ -1,6 +1,6 @@ from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied -from django.shortcuts import redirect, render, get_object_or_404 +from django.shortcuts import get_object_or_404, redirect, render from c3nav.control.forms import AnnouncementForm from c3nav.control.views.base import control_panel_view diff --git a/src/c3nav/control/views/base.py b/src/c3nav/control/views/base.py index 982072bc..dfd6624b 100644 --- a/src/c3nav/control/views/base.py +++ b/src/c3nav/control/views/base.py @@ -1,7 +1,7 @@ from functools import wraps from django.contrib.auth.decorators import login_required -from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin +from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.core.exceptions import PermissionDenied from django.views.generic import TemplateView diff --git a/src/c3nav/control/views/mapupdates.py b/src/c3nav/control/views/mapupdates.py index 12f65531..2d72d708 100644 --- a/src/c3nav/control/views/mapupdates.py +++ b/src/c3nav/control/views/mapupdates.py @@ -10,7 +10,7 @@ from django.shortcuts import redirect, render from django.utils.timezone import make_aware from django.utils.translation import gettext_lazy as _ -from c3nav.control.forms import MapUpdateForm, MapUpdateFilterForm +from c3nav.control.forms import MapUpdateFilterForm, MapUpdateForm from c3nav.control.views.base import control_panel_view from c3nav.mapdata.models import MapUpdate from c3nav.mapdata.tasks import process_map_updates diff --git a/src/c3nav/control/views/mesh.py b/src/c3nav/control/views/mesh.py index ed469207..053295ba 100644 --- a/src/c3nav/control/views/mesh.py +++ b/src/c3nav/control/views/mesh.py @@ -8,12 +8,12 @@ from django.http import Http404 from django.shortcuts import redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from django.views.generic import ListView, DetailView, FormView, UpdateView, TemplateView +from django.views.generic import DetailView, FormView, ListView, TemplateView, UpdateView from c3nav.control.forms import MeshMessageFilterForm from c3nav.control.views.base import ControlPanelMixin from c3nav.mesh.forms import MeshMessageForm, MeshNodeForm -from c3nav.mesh.messages import MeshMessageType, MeshMessage +from c3nav.mesh.messages import MeshMessage, MeshMessageType from c3nav.mesh.models import MeshNode, NodeMessage from c3nav.mesh.utils import get_node_names @@ -35,7 +35,7 @@ class MeshNodeListView(ControlPanelMixin, ListView): def post(self, request): return redirect( - reverse("control.mesh_message.send", kwargs={"msg_type": request.POST.get("send_msg_type", "")}) + reverse("control.mesh.send", kwargs={"msg_type": request.POST.get("send_msg_type", "")}) ) @@ -62,7 +62,7 @@ class MeshNodeEditView(ControlPanelMixin, SuccessMessageMixin, UpdateView): } def get_success_url(self): - return reverse('control.mesh_node.detail', kwargs={'pk': self.get_object().pk}) + return reverse('control.mesh.node.detail', kwargs={'pk': self.get_object().pk}) class MeshMessageListView(ControlPanelMixin, ListView): @@ -130,7 +130,7 @@ class MeshMessageSendView(ControlPanelMixin, FormView): def get_success_url(self): if 'recipient' in self.kwargs and False: - return reverse('control.mesh_node.detail', kwargs={'pk': self.kwargs['recipient']}) + return reverse('control.mesh.node.detail', kwargs={'pk': self.kwargs['recipient']}) else: return self.request.path @@ -145,7 +145,7 @@ class MeshMessageSendView(ControlPanelMixin, FormView): "recipients": form.get_recipients(), "msg_data": form.get_msg_data(), } - return redirect(reverse('control.mesh_message.sending', kwargs={'uuid': uuid})) + return redirect(reverse('control.mesh.sending', kwargs={'uuid': uuid})) class MeshMessageSendingView(ControlPanelMixin, TemplateView): diff --git a/src/c3nav/control/views/users.py b/src/c3nav/control/views/users.py index c6622893..a68e99f3 100644 --- a/src/c3nav/control/views/users.py +++ b/src/c3nav/control/views/users.py @@ -3,7 +3,7 @@ import string from django.contrib import messages from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User -from django.db import transaction, IntegrityError +from django.db import IntegrityError, transaction from django.db.models import Prefetch from django.shortcuts import get_object_or_404, redirect, render from django.utils import timezone @@ -11,8 +11,8 @@ from django.utils.crypto import get_random_string from django.utils.translation import gettext_lazy as _ from django.views.generic import ListView -from c3nav.control.forms import UserPermissionsForm, AccessPermissionForm, UserSpaceAccessForm -from c3nav.control.models import UserSpaceAccess, UserPermissions +from c3nav.control.forms import AccessPermissionForm, UserPermissionsForm, UserSpaceAccessForm +from c3nav.control.models import UserPermissions, UserSpaceAccess from c3nav.control.views.base import ControlPanelMixin, control_panel_view from c3nav.mapdata.models import AccessRestriction from c3nav.mapdata.models.access import AccessPermission @@ -35,7 +35,7 @@ class UserListView(ControlPanelMixin, ListView): @login_required(login_url='site.login') @control_panel_view -def user_detail(request, user): # todo: make class based view +def user_detail(request, user): # todo: make class based view qs = User.objects.select_related( 'permissions', ).prefetch_related( diff --git a/src/c3nav/editor/overlay.py b/src/c3nav/editor/overlay.py index b336e139..e69de29b 100644 --- a/src/c3nav/editor/overlay.py +++ b/src/c3nav/editor/overlay.py @@ -1,2 +0,0 @@ -def editor_get_object_or_404(model, *q): - return get_object_or_404() \ No newline at end of file diff --git a/src/c3nav/mesh/baseformats.py b/src/c3nav/mesh/baseformats.py index 2fe5ed00..ced5e12c 100644 --- a/src/c3nav/mesh/baseformats.py +++ b/src/c3nav/mesh/baseformats.py @@ -1,8 +1,8 @@ import re import struct from abc import ABC, abstractmethod -from dataclasses import dataclass, fields, field, Field -from typing import Any, Sequence, Self +from dataclasses import Field, dataclass, fields +from typing import Any, Self, Sequence from c3nav.mesh.utils import indent_c diff --git a/src/c3nav/mesh/consumers.py b/src/c3nav/mesh/consumers.py index 249ba7e8..5bbb7f96 100644 --- a/src/c3nav/mesh/consumers.py +++ b/src/c3nav/mesh/consumers.py @@ -1,15 +1,15 @@ import traceback from asgiref.sync import async_to_sync -from channels.generic.websocket import WebsocketConsumer, JsonWebsocketConsumer +from channels.generic.websocket import JsonWebsocketConsumer, WebsocketConsumer from django.utils import timezone -from c3nav.mesh.utils import get_mesh_comm_group from c3nav.mesh import messages -from c3nav.mesh.messages import MeshMessage, MESH_BROADCAST_ADDRESS, MeshMessageType, MESH_ROOT_ADDRESS, \ - MESH_NONE_ADDRESS +from c3nav.mesh.messages import (MESH_BROADCAST_ADDRESS, MESH_NONE_ADDRESS, MESH_ROOT_ADDRESS, MeshMessage, + MeshMessageType) from c3nav.mesh.models import MeshNode, NodeMessage from c3nav.mesh.tasks import send_channel_msg +from c3nav.mesh.utils import get_mesh_comm_group # noinspection PyAttributeOutsideInit @@ -34,8 +34,8 @@ class MeshConsumer(WebsocketConsumer): self.remove_dst_nodes(self.dst_nodes) def send_msg(self, msg, sender=None, exclude_uplink_address=None): - #print("sending", msg, MeshMessage.encode(msg).hex(' ', 1)) - #self.log_text(msg.dst, "sending %s" % msg) + # print("sending", msg, MeshMessage.encode(msg).hex(' ', 1)) + # self.log_text(msg.dst, "sending %s" % msg) self.send(bytes_data=MeshMessage.encode(msg)) async_to_sync(self.channel_layer.group_send)("mesh_msg_sent", { "type": "mesh.msg_sent", @@ -44,7 +44,7 @@ class MeshConsumer(WebsocketConsumer): "sender": sender, "uplink": self.uplink_node.address if self.uplink_node else None, "recipient": msg.dst, - #"msg": msg.tojson(), # not doing this part for privacy reasons + # "msg": msg.tojson(), # not doing this part for privacy reasons }) def receive(self, text_data=None, bytes_data=None): @@ -81,7 +81,7 @@ class MeshConsumer(WebsocketConsumer): print('it\'s a broadcast so it\'s also for us') self.log_text(MESH_ROOT_ADDRESS, "received broadcast message, forwarding and handling...") - #print('Received message:', msg) + # print('Received message:', msg) src_node, created = MeshNode.objects.get_or_create(address=msg.src) diff --git a/src/c3nav/mesh/dataformats.py b/src/c3nav/mesh/dataformats.py index 26ab457d..816debfa 100644 --- a/src/c3nav/mesh/dataformats.py +++ b/src/c3nav/mesh/dataformats.py @@ -1,7 +1,7 @@ from dataclasses import dataclass, field from enum import IntEnum, unique -from c3nav.mesh.baseformats import FixedHexFormat, VarArrayFormat, StructType, SimpleFormat, FixedStrFormat +from c3nav.mesh.baseformats import FixedHexFormat, FixedStrFormat, SimpleFormat, StructType, VarArrayFormat class MacAddressFormat(FixedHexFormat): @@ -14,7 +14,6 @@ class MacAddressesListFormat(VarArrayFormat): super().__init__(child_type=MacAddressFormat()) - @unique class LedType(IntEnum): SERIAL = 1 @@ -56,4 +55,4 @@ class FirmwareAppDescription(StructType, no_c_type=True): compile_date: str = field(metadata={"format": FixedStrFormat(16)}) idf_version: str = field(metadata={"format": FixedStrFormat(32)}) app_elf_sha256: str = field(metadata={"format": FixedHexFormat(32)}) - reserv2: list[int] = field(metadata={"format": SimpleFormat('20I')}, repr=False) \ No newline at end of file + reserv2: list[int] = field(metadata={"format": SimpleFormat('20I')}, repr=False) diff --git a/src/c3nav/mesh/forms.py b/src/c3nav/mesh/forms.py index 0f5e0281..84db29d2 100644 --- a/src/c3nav/mesh/forms.py +++ b/src/c3nav/mesh/forms.py @@ -7,7 +7,7 @@ from django.http import Http404 from django.utils.translation import gettext_lazy as _ from c3nav.mesh.dataformats import LedConfig -from c3nav.mesh.messages import MeshMessageType, MeshMessage, MESH_ROOT_ADDRESS, MESH_BROADCAST_ADDRESS +from c3nav.mesh.messages import MESH_BROADCAST_ADDRESS, MESH_ROOT_ADDRESS, MeshMessage, MeshMessageType from c3nav.mesh.models import MeshNode @@ -197,4 +197,4 @@ class ConfigPositionMessageForm(MeshMessageForm): class MeshNodeForm(forms.ModelForm): class Meta: model = MeshNode - fields = ["name"] \ No newline at end of file + fields = ["name"] diff --git a/src/c3nav/mesh/management/commands/mesh_msg_c.py b/src/c3nav/mesh/management/commands/mesh_msg_c.py index 28ab7d68..3107d82f 100644 --- a/src/c3nav/mesh/management/commands/mesh_msg_c.py +++ b/src/c3nav/mesh/management/commands/mesh_msg_c.py @@ -2,9 +2,8 @@ from dataclasses import fields from django.core.management.base import BaseCommand -from c3nav.mesh.dataformats import LedConfig from c3nav.mesh.baseformats import normalize_name -from c3nav.mesh.messages import MeshMessage, MeshMessageType +from c3nav.mesh.messages import MeshMessage from c3nav.mesh.utils import indent_c @@ -43,7 +42,8 @@ class Command(BaseCommand): struct_lines[base_name] = "%s %s;" % (name, base_name.replace('_announce', '')) struct_sizes.append(size) print(code) - print("static_assert(sizeof(%s) == %d, \"size of generated message structs is calculated wrong\");" % (name, size)) + print("static_assert(sizeof(%s) == %d, \"size of generated message structs is calculated wrong\");" % + (name, size)) print() else: nodata.add(msg_type) @@ -53,7 +53,10 @@ class Command(BaseCommand): for line in struct_lines.values(): print(indent_c(line)) print("} mesh_msg_data_t; ") - print("static_assert(sizeof(mesh_msg_data_t) == %d, \"size of generated message structs is calculated wrong\");" % max(struct_sizes)) + print( + "static_assert(sizeof(mesh_msg_data_t) == %d, \"size of generated message structs is calculated wrong\");" + % max(struct_sizes) + ) max_msg_type = max(MeshMessage.get_types().keys()) macro_data = [] diff --git a/src/c3nav/mesh/messages.py b/src/c3nav/mesh/messages.py index 3c63b751..1a532b39 100644 --- a/src/c3nav/mesh/messages.py +++ b/src/c3nav/mesh/messages.py @@ -1,17 +1,15 @@ import re -from dataclasses import asdict, dataclass, field, fields, is_dataclass +from dataclasses import dataclass, field from enum import IntEnum, unique -from itertools import chain from typing import TypeVar import channels from asgiref.sync import async_to_sync -from c3nav.mesh.utils import get_mesh_comm_group, indent_c -from c3nav.mesh.dataformats import (LedConfig, LedConfig, - MacAddressesListFormat, MacAddressFormat, RangeItemType, FirmwareAppDescription) -from c3nav.mesh.baseformats import SimpleFormat, BoolFormat, FixedStrFormat, FixedHexFormat, VarArrayFormat, \ - VarStrFormat, StructType +from c3nav.mesh.baseformats import BoolFormat, FixedStrFormat, SimpleFormat, StructType, VarArrayFormat, VarStrFormat +from c3nav.mesh.dataformats import (FirmwareAppDescription, LedConfig, MacAddressesListFormat, MacAddressFormat, + RangeItemType) +from c3nav.mesh.utils import get_mesh_comm_group MESH_ROOT_ADDRESS = '00:00:00:00:00:00' MESH_NONE_ADDRESS = '00:00:00:00:00:00' @@ -20,6 +18,7 @@ MESH_CHILDREN_ADDRESS = '00:00:00:00:ff:ff' MESH_BROADCAST_ADDRESS = 'ff:ff:ff:ff:ff:ff' NO_LAYER = 0xFF + @unique class MeshMessageType(IntEnum): NOOP = 0x00 @@ -273,4 +272,4 @@ class ConfigUplinkMessage(MeshMessage, msg_id=MeshMessageType.CONFIG_UPLINK): @dataclass class LocateReportRangeMessage(MeshMessage, msg_id=MeshMessageType.LOCATE_REPORT_RANGE): """ report distance to given nodes """ - ranges: dict[str, int] = field(metadata={"format": VarArrayFormat(RangeItemType)}) \ No newline at end of file + ranges: dict[str, int] = field(metadata={"format": VarArrayFormat(RangeItemType)}) diff --git a/src/c3nav/mesh/models.py b/src/c3nav/mesh/models.py index 9702a99a..c2ac8749 100644 --- a/src/c3nav/mesh/models.py +++ b/src/c3nav/mesh/models.py @@ -1,12 +1,14 @@ from collections import UserDict from functools import cached_property from operator import attrgetter -from typing import Mapping, Self, Any +from typing import Any, Mapping, Self -from django.db import models, NotSupportedError +from django.db import NotSupportedError, models from django.utils.translation import gettext_lazy as _ -from c3nav.mesh.messages import MeshMessageType, ChipType, MeshMessage as MeshMessage +from c3nav.mesh.messages import ChipType +from c3nav.mesh.messages import MeshMessage as MeshMessage +from c3nav.mesh.messages import MeshMessageType class MeshNodeQuerySet(models.QuerySet): @@ -42,6 +44,7 @@ class MeshNodeQuerySet(models.QuerySet): except NotSupportedError: pass + class LastMessagesByTypeLookup(UserDict): def __init__(self, node): super().__init__()