Skip to content

Commit

Permalink
fix according to comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Mathias-a committed Oct 10, 2023
1 parent b0d45e4 commit 60f984f
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 33 deletions.
13 changes: 13 additions & 0 deletions backend/root/utils/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,16 @@ def from_db(cls, db, field_names, values): # type: ignore # noqa: ANN001,ANN206
setattr(instance, instance._FTM_LOADED_FIELDS_NAME, loaded_fields) # noqa: FKA01

return instance



class FullCleanSaveMixin(Model):
"""Mixin to call full_clean() before save()."""

class Meta:
abstract = True

def save(self, *args: Any, **kwargs: Any) -> None:
self.full_clean()
super().save(*args, **kwargs)

45 changes: 23 additions & 22 deletions backend/samfundet/models/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from django.db import models
from guardian.shortcuts import assign_perm
from django.utils.translation import gettext as _
from backend.root.utils.mixins import FullCleanSaveMixin

from root.utils import permissions

Expand All @@ -32,7 +33,7 @@ class Meta(AbstractNotification.Meta):
abstract = False


class Tag(models.Model):
class Tag(FullCleanSaveMixin):
# TODO make name case-insensitive
# Kan tvinge alt til lowercase, er enklere.
name = models.CharField(max_length=140)
Expand Down Expand Up @@ -69,7 +70,7 @@ def save(self, *args: Any, **kwargs: Any) -> None:
super().save(*args, **kwargs)


class Image(models.Model):
class Image(FullCleanSaveMixin):
title = models.CharField(max_length=140)
tags = models.ManyToManyField(Tag, blank=True, related_name='images')
image = models.ImageField(upload_to='images/', blank=False, null=False)
Expand Down Expand Up @@ -125,7 +126,7 @@ def impersonated_by(self) -> User:
return self._impersonated_by


class UserPreference(models.Model):
class UserPreference(FullCleanSaveMixin):
"""Group all preferences and config per user."""

class Theme(models.TextChoices):
Expand All @@ -150,7 +151,7 @@ def __str__(self) -> str:
return f'UserPreference ({self.user})'


class Profile(models.Model):
class Profile(FullCleanSaveMixin):
user = models.OneToOneField(User, on_delete=models.CASCADE, blank=True, null=True)
nickname = models.CharField(max_length=30, blank=True, null=True)

Expand All @@ -173,7 +174,7 @@ def save(self, *args: Any, **kwargs: Any) -> None:
assign_perm(perm=permissions.SAMFUNDET_CHANGE_PROFILE, user_or_group=self.user, obj=self)


class Venue(models.Model):
class Venue(FullCleanSaveMixin):
name = models.CharField(max_length=140, blank=True, null=True, unique=True)
slug = models.SlugField(unique=True, null=True)
description = models.TextField(blank=True, null=True)
Expand Down Expand Up @@ -211,7 +212,7 @@ def __str__(self) -> str:
return f'{self.name}'


class ClosedPeriod(models.Model):
class ClosedPeriod(FullCleanSaveMixin):
message_nb = models.TextField(blank=True, null=True, verbose_name='Melding (norsk)')
message_en = models.TextField(blank=True, null=True, verbose_name='Melding (engelsk)')

Expand All @@ -233,7 +234,7 @@ def __str__(self) -> str:


# GANGS ###
class Organization(models.Model):
class Organization(FullCleanSaveMixin):
"""
Object for mapping out the orgs with different gangs, eg. Samfundet, UKA, ISFiT
"""
Expand All @@ -247,7 +248,7 @@ def __str__(self) -> str:
return self.name


class GangType(models.Model):
class GangType(FullCleanSaveMixin):
"""
Type of gang. eg. 'arrangerende', 'kunstnerisk' etc.
"""
Expand All @@ -265,7 +266,7 @@ def __str__(self) -> str:
return f'{self.title_nb}'


class Gang(models.Model):
class Gang(FullCleanSaveMixin):
name_nb = models.CharField(max_length=64, blank=True, null=True, verbose_name='Navn Norsk')
name_en = models.CharField(max_length=64, blank=True, null=True, verbose_name='Navn Engelsk')
abbreviation = models.CharField(max_length=8, blank=True, null=True, verbose_name='Forkortelse')
Expand Down Expand Up @@ -304,7 +305,7 @@ def __str__(self) -> str:
return f'{self.gang_type} - {self.name_nb}'


class InformationPage(models.Model):
class InformationPage(FullCleanSaveMixin):
slug_field = models.SlugField(
max_length=64,
blank=True,
Expand Down Expand Up @@ -333,7 +334,7 @@ def __str__(self) -> str:
return f'{self.slug_field}'


class BlogPost(models.Model):
class BlogPost(FullCleanSaveMixin):
title_nb = models.CharField(max_length=64, blank=True, null=True, verbose_name='Tittel (norsk)')
text_nb = models.TextField(blank=True, null=True, verbose_name='Tekst (norsk)')

Expand All @@ -356,7 +357,7 @@ def __str__(self) -> str:
return f'{self.title_nb} {self.published_at}'


class Table(models.Model):
class Table(FullCleanSaveMixin):
name_nb = models.CharField(max_length=64, unique=True, blank=True, null=True, verbose_name='Navn (norsk)')
description_nb = models.CharField(max_length=64, blank=True, null=True, verbose_name='Beskrivelse (norsk)')

Expand All @@ -381,7 +382,7 @@ def __str__(self) -> str:
return f'{self.name_nb}'


class Reservation(models.Model):
class Reservation(FullCleanSaveMixin):
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=64, blank=True, verbose_name='Navn')
email = models.EmailField(max_length=64, blank=True, verbose_name='Epost')
Expand All @@ -408,7 +409,7 @@ def __str__(self) -> str:
return f'{self.name}'


class FoodPreference(models.Model):
class FoodPreference(FullCleanSaveMixin):
name_nb = models.CharField(max_length=64, unique=True, blank=True, null=True, verbose_name='Navn (norsk)')
name_en = models.CharField(max_length=64, blank=True, null=True, verbose_name='Navn (engelsk)')

Expand All @@ -423,7 +424,7 @@ def __str__(self) -> str:
return f'{self.name_nb}'


class FoodCategory(models.Model):
class FoodCategory(FullCleanSaveMixin):
name_nb = models.CharField(max_length=64, unique=True, blank=True, null=True, verbose_name='Navn (norsk)')
name_en = models.CharField(max_length=64, blank=True, null=True, verbose_name='Navn (engelsk)')
order = models.PositiveSmallIntegerField(blank=True, null=True, unique=True)
Expand All @@ -439,7 +440,7 @@ def __str__(self) -> str:
return f'{self.name_nb}'


class MenuItem(models.Model):
class MenuItem(FullCleanSaveMixin):
name_nb = models.CharField(max_length=64, unique=True, blank=True, null=True, verbose_name='Navn (norsk)')
description_nb = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (norsk)')

Expand All @@ -465,7 +466,7 @@ def __str__(self) -> str:
return f'{self.name_nb}'


class Menu(models.Model):
class Menu(FullCleanSaveMixin):
name_nb = models.CharField(max_length=64, unique=True, blank=True, null=True, verbose_name='Navn (norsk)')
description_nb = models.TextField(blank=True, null=True, verbose_name='Beskrivelse (norsk)')

Expand All @@ -485,7 +486,7 @@ def __str__(self) -> str:
return f'{self.name_nb}'


class Saksdokument(models.Model):
class Saksdokument(FullCleanSaveMixin):
title_nb = models.CharField(max_length=80, blank=True, null=True, verbose_name='Tittel (Norsk)')
title_en = models.CharField(max_length=80, blank=True, null=True, verbose_name='Tittel (Engelsk)')
publication_date = models.DateTimeField(blank=True, null=True)
Expand All @@ -510,7 +511,7 @@ def __str__(self) -> str:
return f'{self.title_nb}'


class Booking(models.Model):
class Booking(FullCleanSaveMixin):
name = models.CharField(max_length=64, blank=True, null=True)
text = models.TextField(blank=True, null=True)
from_dt = models.DateTimeField(blank=True, null=True)
Expand Down Expand Up @@ -562,7 +563,7 @@ def save(self, *args: Any, **kwargs: Any) -> None:
super().save(*args, **kwargs)


class Infobox(models.Model):
class Infobox(FullCleanSaveMixin):
title_nb = models.CharField(max_length=60, blank=False, null=False, verbose_name='Infoboks titel (norsk)')
text_nb = models.CharField(max_length=255, blank=False, null=False, verbose_name='Infoboks tekst (norsk)')

Expand All @@ -585,7 +586,7 @@ def __str__(self) -> str:
return f'{self.title_nb}'


class TextItem(models.Model):
class TextItem(FullCleanSaveMixin):
key = models.CharField(max_length=40, blank=False, null=False, unique=True, primary_key=True)
text_nb = models.TextField()
text_en = models.TextField()
Expand All @@ -598,7 +599,7 @@ def __str__(self) -> str:
return f'{self.key}'


class KeyValue(models.Model):
class KeyValue(FullCleanSaveMixin):
"""
Model for environment variables in the database.
Should not be used for secrets.
Expand Down
20 changes: 10 additions & 10 deletions backend/samfundet/models/recruitment.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@

from django.db import models

from backend.root.utils.mixins import FullCleanSaveMixin

from .general import Organization, User, Gang


class Recruitment(models.Model):
class Recruitment(FullCleanSaveMixin):
name_nb = models.CharField(max_length=100, help_text='Name of the recruitment')
name_en = models.CharField(max_length=100, help_text='Name of the recruitment')
visible_from = models.DateTimeField(help_text='When it becomes visible for applicants')
Expand All @@ -26,7 +28,7 @@ class Recruitment(models.Model):
def is_active(self) -> bool:
return self.visible_from < timezone.now() < self.actual_application_deadline

def save(self, *args: tuple, **kwargs: dict) -> None:
def clean(self, *args: tuple, **kwargs: dict) -> None:
# All times should be in the future
now = timezone.now()
if any(
Expand All @@ -53,13 +55,13 @@ def save(self, *args: tuple, **kwargs: dict) -> None:
if self.reprioritization_deadline_for_applicant > self.reprioritization_deadline_for_groups:
raise ValidationError('Reprioritization deadline for applicants should be before reprioritization deadline for groups')

super().save(*args, **kwargs)
super().clean()

def __str__(self) -> str:
return f'Recruitment: {self.name_en} at {self.organization}'


class RecruitmentPosition(models.Model):
class RecruitmentPosition(FullCleanSaveMixin):
name_nb = models.CharField(max_length=100, help_text='Name of the position')
name_en = models.CharField(max_length=100, help_text='Name of the position')

Expand Down Expand Up @@ -96,7 +98,7 @@ def __str__(self) -> str:
return f'Position: {self.name_en} in {self.recruitment}'


class InterviewRoom(models.Model):
class InterviewRoom(FullCleanSaveMixin):
name = models.CharField(max_length=255, help_text='Name of the room')
location = models.CharField(max_length=255, help_text='Physical location, eg. campus')
start_time = models.DateTimeField(help_text='Start time of availability')
Expand All @@ -114,7 +116,7 @@ def clean(self) -> None:
super().clean()


class Interview(models.Model):
class Interview(FullCleanSaveMixin):
# User visible fields
interview_time = models.DateTimeField(help_text='The time of the interview', null=True, blank=True)
interview_location = models.CharField(max_length=255, help_text='The location of the interview', null=True, blank=True)
Expand All @@ -131,7 +133,7 @@ class Interview(models.Model):
notes = models.TextField(help_text='Notes for the interview', null=True, blank=True)


class RecruitmentAdmission(models.Model):
class RecruitmentAdmission(FullCleanSaveMixin):
admission_text = models.TextField(help_text='Admission text for the admission')
recruitment_position = models.ForeignKey(
RecruitmentPosition, on_delete=models.CASCADE, help_text='The recruitment position that is recruiting', related_name='admissions'
Expand Down Expand Up @@ -180,8 +182,6 @@ def save(self, *args: tuple, **kwargs: dict) -> None:
self.interview = shared_interview.interview
else:
# Create a new interview instance if needed
new_interview = Interview()
new_interview.save()
self.interview = new_interview
self.interview = Interview.objects.create()

super(RecruitmentAdmission, self).save(*args, **kwargs)
6 changes: 5 additions & 1 deletion backend/samfundet/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,11 @@ def get_queryset(self) -> QuerySet[User]:
# Exclude users who have any admissions for the given recruitment that have an interview_time
users_without_interviews = User.objects.filter(admissions__recruitment=recruitment).annotate(
num_interviews=Count(
Case(When(admissions__recruitment=recruitment, then='admissions__interview__interview_time'), default=None, output_field=None)
Case(
When(admissions__recruitment=recruitment, then='admissions__interview__interview_time'),
default=None,
output_field=None,
)
)
).filter(num_interviews=0)
return users_without_interviews
Expand Down

0 comments on commit 60f984f

Please sign in to comment.