diff --git a/doorcontrol/models.py b/doorcontrol/models.py index d697cbe..ab71498 100644 --- a/doorcontrol/models.py +++ b/doorcontrol/models.py @@ -22,6 +22,9 @@ class Door(models.Model): help_text="Membershipworks field that grants members access to this door", ) + def __str__(self): + return self.name + @property def controller(self) -> DoorController: return DoorController( @@ -30,9 +33,6 @@ class Door(models.Model): settings.HID_DOOR_PASSWORD, ) - def __str__(self): - return self.name - @cached_property def card_formats(self): return self.controller.get_cardFormats() @@ -149,8 +149,6 @@ class HIDEventQuerySet(models.QuerySet): class HIDEvent(models.Model): - objects = HIDEventQuerySet.as_manager() - class EventType(models.IntegerChoices): DENIED_ACCESS_CARD_NOT_FOUND = 1022, "Denied Access: Card Not Found" DENIED_ACCESS_ACCESS_PIN_NOT_FOUND = 1023, "Denied Access Access: PIN Not Found" @@ -224,6 +222,20 @@ class HIDEvent(models.Model): db_persist=False, ) + objects = HIDEventQuerySet.as_manager() + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["door", "timestamp", "event_type"], name="unique_hidevent" + ) + ] + db_table = "hidevent" + ordering = ("-timestamp",) + + def __str__(self): + return f"{self.door.name} {self.timestamp} - {self.description}" + @classmethod def from_xml_attributes(cls, door: Door, attrib: dict[str, str]): field_lookup = { @@ -289,9 +301,6 @@ class HIDEvent(models.Model): return event_types.get(self.event_type, f"Unknown Event Type {self.event_type}") - def __str__(self): - return f"{self.door.name} {self.timestamp} - {self.description}" - def decoded_card_number(self) -> str | None: """Requires annotations from `with_decoded_card_number`""" if self.raw_card_number is None: @@ -303,12 +312,3 @@ class HIDEvent(models.Model): return "Invalid" else: return "Not 26 bit card" - - class Meta: - constraints = [ - models.UniqueConstraint( - fields=["door", "timestamp", "event_type"], name="unique_hidevent" - ) - ] - db_table = "hidevent" - ordering = ("-timestamp",) diff --git a/membershipworks/models.py b/membershipworks/models.py index 1f8bb03..aff6719 100644 --- a/membershipworks/models.py +++ b/membershipworks/models.py @@ -88,13 +88,13 @@ class Flag(BaseModel): name = models.TextField(null=True, blank=True) type = models.CharField(max_length=6) - def __str__(self): - return f"{self.name} ({self.type})" - class Meta: db_table = "flag" ordering = ("name",) + def __str__(self): + return f"{self.name} ({self.type})" + class MemberQuerySet(models.QuerySet): # TODO: maybe rename to reflect EXISTS? @@ -122,8 +122,6 @@ class MemberQuerySet(models.QuerySet): # TODO: is this still a temporal table? class Member(BaseModel): - objects = MemberQuerySet.as_manager() - uid = models.CharField(max_length=24, primary_key=True) year_of_birth = models.TextField(db_column="Year of Birth", null=True, blank=True) account_name = models.TextField(db_column="Account Name", null=True, blank=True) @@ -264,8 +262,7 @@ class Member(BaseModel): "Waiver form signed and on file date.": "%m/%d/%Y", } - def __str__(self): - return f"{self.account_name}" + objects = MemberQuerySet.as_manager() class Meta: db_table = "members" @@ -276,6 +273,9 @@ class Member(BaseModel): models.Index(fields=["last_name"], name="last_name_idx"), ] + def __str__(self): + return f"{self.account_name}" + @classmethod def from_user(cls, user) -> "Member | None": if hasattr(user, "ldap_user"): @@ -304,9 +304,6 @@ class MemberFlag(BaseModel): ) flag = models.ForeignKey(Flag, on_delete=models.PROTECT) - def __str__(self): - return f"{self.member} - {self.flag}" - class Meta: db_table = "memberflag" constraints = [ @@ -315,6 +312,9 @@ class MemberFlag(BaseModel): ) ] + def __str__(self): + return f"{self.member} - {self.flag}" + class Transaction(BaseModel): sid = models.CharField(max_length=256, null=True, blank=True) @@ -364,24 +364,24 @@ class Transaction(BaseModel): "_dp": None, } - def __str__(self): - return f"{self.type} [{self.member if self.member else self.name}] {self.timestamp}" - class Meta: db_table = "transactions" + def __str__(self): + return f"{self.type} [{self.member if self.member else self.name}] {self.timestamp}" + class EventCategory(models.Model): id = models.IntegerField(primary_key=True) title = models.TextField() + def __str__(self): + return self.title + @classmethod def from_api_dict(cls, id: int, data): return cls(id=id, title=data["ttl"]) - def __str__(self): - return self.title - class Event(BaseModel): class EventCalendar(models.IntegerChoices): @@ -433,13 +433,13 @@ class Event(BaseModel): _allowed_missing_fields = ["cap", "edp", "adn"] + def __str__(self): + return self.unescaped_title + @property def unescaped_title(self): return nh3.clean(self.title, tags=set()) - def __str__(self): - return self.unescaped_title - class EventInstructor(models.Model): name = models.TextField(blank=True) @@ -526,8 +526,6 @@ class EventExtManager(models.Manager): class EventExt(Event): """Extension of `Event` to capture some fields not supported in MembershipWorks""" - objects = EventExtManager.from_queryset(EventExtQuerySet)() - instructor = models.ForeignKey( EventInstructor, on_delete=models.PROTECT, null=True, blank=True ) @@ -557,6 +555,12 @@ class EventExt(Event): should_survey = models.BooleanField(default=False) survey_email_sent = models.BooleanField(default=False) + objects = EventExtManager.from_queryset(EventExtQuerySet)() + + class Meta: + verbose_name = "event" + ordering = ["-start"] + def get_absolute_url(self) -> str: return reverse("membershipworks:event-detail", kwargs={"eid": self.eid}) @@ -581,10 +585,6 @@ class EventExt(Event): and getattr(self, "total_due_to_instructor") is not None ) - class Meta: - verbose_name = "event" - ordering = ["-start"] - if TYPE_CHECKING: diff --git a/paperwork/models.py b/paperwork/models.py index 3c2d6b3..cb2c042 100644 --- a/paperwork/models.py +++ b/paperwork/models.py @@ -20,14 +20,14 @@ class AbstractAudit(models.Model): good = models.BooleanField(default=False) notes = models.CharField(max_length=255, blank=True) - def __str__(self) -> str: - return f"{'Good' if self.good else 'Bad'} audit at {self.date} by {self.user}" - class Meta: abstract = True ordering = ["date"] get_latest_by = ["date"] + def __str__(self) -> str: + return f"{'Good' if self.good else 'Bad'} audit at {self.date} by {self.user}" + class CmsRedRiverVeteransScholarship(models.Model): serial = models.AutoField(primary_key=True) @@ -61,12 +61,12 @@ class CmsRedRiverVeteransScholarship(models.Model): db_column="Program Status", max_length=16, blank=True, null=True ) - def __str__(self) -> str: - return f"{self.program_name} {self.member_name}" - class Meta: db_table = "CMS Red River Veterans Scholarship" + def __str__(self) -> str: + return f"{self.program_name} {self.member_name}" + class DepartmentQuerySet(models.QuerySet): def filter_by_shop_lead(self, member: Member) -> models.QuerySet["Department"]: @@ -80,8 +80,6 @@ class DepartmentQuerySet(models.QuerySet): class Department(models.Model): - objects = DepartmentQuerySet.as_manager() - name = models.CharField( max_length=64, validators=[RegexValidator("^[-_ A-Za-z0-9]*$")], @@ -101,6 +99,8 @@ class Department(models.Model): ) list_reply_to_address = models.EmailField(max_length=254, blank=True) + objects = DepartmentQuerySet.as_manager() + def __str__(self) -> str: return self.name @@ -123,13 +123,13 @@ class CertificationDefinition(models.Model): name = models.CharField(max_length=255) department = models.ForeignKey(Department, models.PROTECT) - def __str__(self) -> str: - return f"{self.name} <{self.department}>" - class Meta: db_table = "Certification Definitions" ordering = ("name", "department") + def __str__(self) -> str: + return f"{self.name} <{self.department}>" + def latest_version(self) -> "CertificationVersion": return self.certificationversion_set.latest() @@ -157,8 +157,6 @@ class CertificationVersionManager(models.Manager["CertificationVersion"]): class CertificationVersion(models.Model): - objects = CertificationVersionManager() - definition = models.ForeignKey(CertificationDefinition, on_delete=models.PROTECT) major = models.PositiveSmallIntegerField() minor = models.PositiveSmallIntegerField() @@ -166,8 +164,7 @@ class CertificationVersion(models.Model): prerelease = models.CharField(max_length=255, blank=True) approval_date = models.DateField(blank=True, null=True) - def __str__(self) -> str: - return f"{self.definition} [{self.semantic_version()}]" + objects = CertificationVersionManager() class Meta: constraints = [ @@ -187,6 +184,9 @@ class CertificationVersion(models.Model): get_latest_by = ("major", "minor", "patch", "prerelease", "approval_date") base_manager_name = "objects" + def __str__(self) -> str: + return f"{self.definition} [{self.semantic_version()}]" + def semantic_version(self) -> VersionInfo: return VersionInfo( self.major or 0, @@ -224,9 +224,6 @@ class Certification(models.Model): shop_lead_notified = models.DateTimeField(blank=True, null=True) notes = models.CharField(max_length=255, blank=True, null=True) - def __str__(self) -> str: - return f"{self.name} - {self.certification_version}" - class Meta: db_table = "Certifications" permissions = [ @@ -236,6 +233,9 @@ class Certification(models.Model): ), ] + def __str__(self) -> str: + return f"{self.name} - {self.certification_version}" + class CertificationAudit(AbstractAudit): certification = models.ForeignKey( @@ -255,12 +255,12 @@ class InstructorOrVendor(models.Model): db_column="email address", max_length=255, blank=True, null=True ) - def __str__(self) -> str: - return f"{self.name}" - class Meta: db_table = "Instructors and Vendors" + def __str__(self) -> str: + return f"{self.name}" + class SpecialProgram(models.Model): program_name = models.CharField( @@ -292,12 +292,12 @@ class SpecialProgram(models.Model): db_column="Program Status", max_length=16, blank=True, null=True ) - def __str__(self) -> str: - return self.program_name - class Meta: db_table = "Special_Programs" + def __str__(self) -> str: + return self.program_name + class Waiver(models.Model): number = models.AutoField(db_column="Number", primary_key=True) @@ -319,12 +319,12 @@ class Waiver(models.Model): guardian_date = models.DateField(db_column="Guardian Date", blank=True, null=True) notes = models.CharField(max_length=255, blank=True, null=True) - def __str__(self) -> str: - return f"{self.name} {self.date}" - class Meta: db_table = "Waivers" + def __str__(self) -> str: + return f"{self.name} {self.date}" + class WaiverAudit(AbstractAudit): waiver = models.ForeignKey(Waiver, on_delete=models.CASCADE, related_name="audits") diff --git a/pyproject.toml b/pyproject.toml index 85830b3..41b6ec0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ admin_email = "cmsmanage.django_q2_admin_email_reporter:AdminEmailReporter" line-length = 88 [tool.ruff.lint] -select = ["E4", "E7", "E9", "F", "I", "C4", "UP", "PERF", "PL", "SIM", "FIX003"] +select = ["E4", "E7", "E9", "F", "I", "C4", "UP", "PERF", "PL", "SIM", "FIX003", "DJ012"] [tool.ruff.lint.isort] known-first-party = [ diff --git a/rentals/models.py b/rentals/models.py index 7e6eaa6..4bd029a 100644 --- a/rentals/models.py +++ b/rentals/models.py @@ -33,17 +33,6 @@ class LockerUnit(models.Model): rows = models.PositiveIntegerField(default=5) columns = models.PositiveIntegerField(default=2) - def save(self, *args, **kwargs): - if self._state.adding: - # Create LockerInfo for each locker - with transaction.atomic(): - super().save(self, *args, **kwargs) - for column in range(self.columns): - for row in range(self.rows): - self.lockers.create(column=column + 1, row=row + 1) - else: - super().save(self, *args, **kwargs) - class Meta: # TODO: add constraint to check for letter overlaps constraints = [ @@ -56,6 +45,17 @@ class LockerUnit(models.Model): last_number = self.first_number + self.columns * self.rows return f"{self.bank.name} (Unit {last_letter}{self.first_number}-{self.first_letter}{last_number})" + def save(self, *args, **kwargs): + if self._state.adding: + # Create LockerInfo for each locker + with transaction.atomic(): + super().save(self, *args, **kwargs) + for column in range(self.columns): + for row in range(self.rows): + self.lockers.create(column=column + 1, row=row + 1) + else: + super().save(self, *args, **kwargs) + def letter_for_column(self, column: int) -> str: return chr(column + ord(self.first_letter)) @@ -91,10 +91,6 @@ class LockerInfo(models.Model): ) notes = models.TextField(blank=True) - def clean(self): - if self.reserved and self.renter is not None: - raise ValidationError("Locker cannot both be reserved and rented!") - class Meta: constraints = [ models.UniqueConstraint( @@ -106,6 +102,13 @@ class LockerInfo(models.Model): ), ] + def __str__(self): + return f"{self.locker_unit}-{self.address} [{self.renter}]" + + def clean(self): + if self.reserved and self.renter is not None: + raise ValidationError("Locker cannot both be reserved and rented!") + @property def available(self) -> bool: return self.renter is None and not self.reserved @@ -132,6 +135,3 @@ class LockerInfo(models.Model): ) def address(self) -> str: return f"{self.letter}{self.number}" - - def __str__(self): - return f"{self.locker_unit}-{self.address} [{self.renter}]" diff --git a/tasks/models.py b/tasks/models.py index 4f71c12..692a50a 100644 --- a/tasks/models.py +++ b/tasks/models.py @@ -90,18 +90,18 @@ class GroupToolSubscription(SubscriptionSettings): group = models.ForeignKey(Group, on_delete=models.CASCADE) tool = models.ForeignKey(Tool, on_delete=models.CASCADE) - def get_task_subscriptions(self): - for task in self.tool.task_set.all(): - yield GroupTaskSubscription( - days_before=self.days_before, group=self.group, task=task - ) - class Meta: unique_together = (("group", "tool"),) def __str__(self): return f"{self.group}-{self.tool}, {super().__str__()}" + def get_task_subscriptions(self): + for task in self.tool.task_set.all(): + yield GroupTaskSubscription( + days_before=self.days_before, group=self.group, task=task + ) + class GroupTaskSubscription(SubscriptionSettings): group = models.ForeignKey(Group, on_delete=models.CASCADE) @@ -110,6 +110,9 @@ class GroupTaskSubscription(SubscriptionSettings): class Meta: unique_together = (("group", "task"),) + def __str__(self): + return f"{self.group}-{self.task}, {super().__str__()}" + @property def should_remind(self): next_recurrence = self.task.next_recurrence @@ -118,9 +121,6 @@ class GroupTaskSubscription(SubscriptionSettings): time_until_overdue = next_recurrence - datetime.datetime.now() return self.task.is_overdue or (time_until_overdue.days <= self.days_before) - def __str__(self): - return f"{self.group}-{self.task}, {super().__str__()}" - class Event(models.Model): task = models.ForeignKey(Task, on_delete=models.CASCADE) @@ -128,9 +128,9 @@ class Event(models.Model): date = models.DateField() notes = MarkdownxField(blank=True) + def __str__(self): + return f"{self.task}: {self.user} {self.date}" + @property def notes_html(self): return markdown_to_clean_html(self.notes) - - def __str__(self): - return f"{self.task}: {self.user} {self.date}"