doorcontrol: Add annotations that decode the hex card number
This commit is contained in:
parent
67f13ce580
commit
906f662419
@ -30,9 +30,10 @@ class HIDEventAdmin(admin.ModelAdmin):
|
|||||||
"event_type",
|
"event_type",
|
||||||
IsRedFilter,
|
IsRedFilter,
|
||||||
]
|
]
|
||||||
|
readonly_fields = ["decoded_card_number"]
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return super().get_queryset(request).with_is_red()
|
return super().get_queryset(request).with_is_red().with_decoded_card_number()
|
||||||
|
|
||||||
@admin.display(boolean=True)
|
@admin.display(boolean=True)
|
||||||
def is_red(self, obj):
|
def is_red(self, obj):
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import ExpressionWrapper, Q
|
from django.db.models import ExpressionWrapper, F, Func, Q
|
||||||
|
from django.db.models.functions import Mod
|
||||||
|
|
||||||
|
|
||||||
class HIDEventQuerySet(models.QuerySet):
|
class HIDEventQuerySet(models.QuerySet):
|
||||||
@ -28,6 +29,42 @@ class HIDEventQuerySet(models.QuerySet):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def with_decoded_card_number(self):
|
||||||
|
# TODO: CONV and BIT_COUNT are MySQL/MariaDB specific
|
||||||
|
class Conv(Func):
|
||||||
|
function = "CONV"
|
||||||
|
arity = 3
|
||||||
|
# This is technically not true, but fine for my purposes
|
||||||
|
output_field = models.IntegerField()
|
||||||
|
|
||||||
|
class BitCount(Func):
|
||||||
|
function = "BIT_COUNT"
|
||||||
|
arity = 1
|
||||||
|
|
||||||
|
return (
|
||||||
|
self.alias(card_number=Conv(F("raw_card_number"), 16, 10))
|
||||||
|
.alias(more_than_26_bits=F("card_number").bitrightshift(26))
|
||||||
|
.annotate(card_is_26_bit=Q(more_than_26_bits=0))
|
||||||
|
.alias(
|
||||||
|
parity_a=Mod(
|
||||||
|
BitCount(F("card_number").bitrightshift(1).bitand(0xFFF)), 2
|
||||||
|
),
|
||||||
|
parity_b=Mod(
|
||||||
|
BitCount(F("card_number").bitrightshift(13).bitand(0xFFF)), 2
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
card_is_valid_26_bit=~Q(parity_a=F("card_number").bitand(1))
|
||||||
|
& Q(parity_b=F("card_number").bitrightshift(25).bitand(1))
|
||||||
|
)
|
||||||
|
.annotate(
|
||||||
|
card_number_26_bit=F("card_number").bitrightshift(1).bitand(0xFFFF),
|
||||||
|
card_facility_code_26_bit=F("card_number")
|
||||||
|
.bitrightshift(17)
|
||||||
|
.bitand(0xFF),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class HIDEvent(models.Model):
|
class HIDEvent(models.Model):
|
||||||
objects = HIDEventQuerySet.as_manager()
|
objects = HIDEventQuerySet.as_manager()
|
||||||
@ -121,6 +158,18 @@ class HIDEvent(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.door_name} {self.timestamp} - {self.description}"
|
return f"{self.door_name} {self.timestamp} - {self.description}"
|
||||||
|
|
||||||
|
def decoded_card_number(self) -> str:
|
||||||
|
"""Requires annotations from `with_decoded_card_number`"""
|
||||||
|
if self.raw_card_number is None:
|
||||||
|
return None
|
||||||
|
elif self.card_is_26_bit:
|
||||||
|
if self.card_is_valid_26_bit:
|
||||||
|
return f"{self.card_facility_code_26_bit} - {self.card_number_26_bit}"
|
||||||
|
else:
|
||||||
|
return "Invalid"
|
||||||
|
else:
|
||||||
|
return "Not 26 bit card"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
models.UniqueConstraint(
|
models.UniqueConstraint(
|
||||||
|
Loading…
Reference in New Issue
Block a user