MAKENTNU/web

View on GitHub
src/make_queue/models/course.py

Summary

Maintainability
A
35 mins
Test Coverage
from django.db import models
from django.db.models.constraints import CheckConstraint
from django.db.models.query_utils import Q
from django.utils.translation import gettext_lazy as _
 
from card.modelfields import CardNumberField
from users.models import User
from .fields import UsernameField
 
 
# `3DPrinterCourse` would be a syntactically invalid name :(
class Printer3DCourse(models.Model):
class Status(models.TextChoices):
REGISTERED = 'registered', _("Registered")
# Translators: See the Norwegian and English versions of this page for
# a translation of "Building security":
# https://i.ntnu.no/wiki/-/wiki/Norsk/Vakt+og+service+p%C3%A5+campus
SENT = 'sent', _("Sent to Building security")
ACCESS = 'access', _("Access granted")
 
user = models.OneToOneField(
to=User,
on_delete=models.CASCADE,
null=True,
related_name='printer_3d_course',
verbose_name=_("user"),
)
username = UsernameField(max_length=32, blank=True, unique=True, verbose_name=_("username"))
name = models.CharField(max_length=256, blank=True, verbose_name=_("full name"))
# Set `null=True` even when it's a string-based field, as `null` is the only value not checked by the unique constraint
_card_number = CardNumberField(null=True, blank=True, unique=True) # Card number backing field. Use card_number property instead
 
date = models.DateField(verbose_name=_("course date"))
status = models.CharField(choices=Status.choices, max_length=20, default=Status.REGISTERED, verbose_name=_("status"))
raise3d_course = models.BooleanField(default=False, verbose_name=_("Raise3D course"))
sla_course = models.BooleanField(default=False, verbose_name=_("SLA course"))
last_modified = models.DateTimeField(auto_now=True, verbose_name=_("last modified"))
 
class Meta:
constraints = (
CheckConstraint(check=Q(user__isnull=True) | Q(_card_number__isnull=True), name="user_or_cardnumber_null"),
)
verbose_name = _("3D printer course")
verbose_name_plural = _("3D printer courses")
 
Cyclomatic complexity is too high in method save. (6)
Function `save` has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring.
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
if self.pk is None: # Creation of new object
self._connect_to_user()
else:
old = Printer3DCourse.objects.get(pk=self.pk)
if old.username != self.username:
# Changed username, connect to new user
self._connect_to_user()
elif self.user:
# Update username in the rare case that a user changes their username
self.username = self.user.username
 
# If user is set, use card number from user
if self.user and self._card_number:
self.user.card_number = self._card_number
self._card_number = None
self.user.save()
 
super().save(force_insert, force_update, using, update_fields)
 
def _connect_to_user(self):
"""
Connect to user with username if user exists.
"""
try:
self.user = User.objects.get(username=self.username)
except User.DoesNotExist:
pass
 
@property
def card_number(self):
if self.user:
return self.user.card_number
return self._card_number
 
@card_number.setter
def card_number(self, card_number):
if self.user:
self.user.card_number = card_number
self.user.save()
self._card_number = None
else:
self._card_number = card_number
 
def get_user_display_name(self):
full_name = self.user.get_full_name() if self.user else self.name
return str(full_name or self.user or self.username)