__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" from django.db import models from django.utils import timezone from ..managers import FellowshipNominationVotingRoundQuerySet class FellowshipNomination(models.Model): college = models.ForeignKey( "colleges.College", on_delete=models.PROTECT, related_name="nominations" ) profile = models.ForeignKey( "profiles.Profile", on_delete=models.CASCADE, related_name="fellowship_nominations", ) nominated_by = models.ForeignKey( "scipost.Contributor", on_delete=models.CASCADE, related_name="fellowship_nominations_initiated", ) nominated_on = models.DateTimeField(default=timezone.now) nominator_comments = models.TextField( help_text=( "You can use plain text, Markdown or reStructuredText; see our " '<a href="/markup/help/" target="_blank">markup help</a> pages.' ), blank=True, ) fellowship = models.OneToOneField( "colleges.Fellowship", on_delete=models.CASCADE, related_name="nomination", blank=True, null=True, ) class Meta: ordering = [ "profile", "college", ] verbose_name_plural = "Fellowship Nominations" def __str__(self): return ( f"{self.profile} to {self.college} " f'on {self.nominated_on.strftime("%Y-%m-%d")}' ) class FellowshipNominationEvent(models.Model): nomination = models.ForeignKey( "colleges.FellowshipNomination", on_delete=models.CASCADE, related_name="events" ) description = models.TextField() on = models.DateTimeField(default=timezone.now) class Meta: ordering = ["-on"] verbose_name_plural = "Fellowhip Nomination Events" def __str__(self): return f"Event for {self.nomination}" class FellowshipNominationVotingRound(models.Model): nomination = models.ForeignKey( "colleges.FellowshipNomination", on_delete=models.CASCADE, related_name="voting_rounds", ) eligible_to_vote = models.ManyToManyField( "colleges.Fellowship", related_name="voting_rounds_eligible_to_vote_in", blank=True, ) voting_opens = models.DateTimeField() voting_deadline = models.DateTimeField() objects = FellowshipNominationVotingRoundQuerySet.as_manager() class Meta: ordering = ["nomination__profile__last_name"] verbose_name_plural = "Fellowship Nomination Voting Rounds" def __str__(self): return ( f'Voting round ({self.voting_opens.strftime("%Y-%m-%d")} -' f' {self.voting_deadline.strftime("%Y-%m-%d")}) for {self.nomination}' ) class FellowshipNominationVote(models.Model): VOTE_AGREE = "agree" VOTE_ABSTAIN = "abstain" VOTE_DISAGREE = "disagree" VOTE_CHOICES = ( (VOTE_AGREE, "Agree"), (VOTE_ABSTAIN, "Abstain"), (VOTE_DISAGREE, "Disagree"), ) voting_round = models.ForeignKey( "colleges.FellowshipNominationVotingRound", on_delete=models.CASCADE, related_name="votes", ) fellow = models.ForeignKey( "colleges.Fellowship", on_delete=models.CASCADE, related_name="fellowship_nomination_votes", ) vote = models.CharField(max_length=16, choices=VOTE_CHOICES) on = models.DateTimeField(blank=True, null=True) comments = models.TextField( help_text=( "You can use plain text, Markdown or reStructuredText; see our " '<a href="/markup/help/" target="_blank">markup help</a> pages.' ), blank=True, ) class Meta: ordering = [ "voting_round", ] verbose_name_plural = "Fellowship Nomination Votes" class FellowshipNominationDecision(models.Model): nomination = models.OneToOneField( "colleges.FellowshipNomination", on_delete=models.CASCADE, related_name="decision", ) OUTCOME_ELECTED = "elected" OUTCOME_NOT_ELECTED = "notelected" OUTCOME_CHOICES = ( (OUTCOME_ELECTED, "Elected"), (OUTCOME_NOT_ELECTED, "Not elected"), ) outcome = models.CharField(max_length=16, choices=OUTCOME_CHOICES) fixed_on = models.DateTimeField(default=timezone.now) comments = models.TextField( help_text=( "You can use plain text, Markdown or reStructuredText; see our " '<a href="/markup/help/" target="_blank">markup help</a> pages.' ), blank=True, ) class Meta: ordering = [ "nomination", ] verbose_name_plural = "Fellowship Nomination Decisions" def __str__(self): return f"Decision for {self.nomination}: {self.get_outcome_display()}" @property def elected(self): return self.outcome == self.OUTCOME_ELECTED class FellowshipInvitation(models.Model): nomination = models.OneToOneField( "colleges.FellowshipNomination", on_delete=models.CASCADE, related_name="invitation", ) invited_on = models.DateTimeField(blank=True, null=True) RESPONSE_NOT_YET_INVITED = "notyetinvited" RESPONSE_INVITED = "invited" RESPONSE_REINVITED = "reinvited" RESPONSE_MULTIPLY_REINVITED = "multireinvited" RESPONSE_UNRESPONSIVE = "unresponsive" RESPONSE_ACCEPTED = "accepted" RESPONSE_POSTPONED = "postponed" RESPONSE_DECLINED = "declined" RESPONSE_CHOICES = ( (RESPONSE_NOT_YET_INVITED, "Not yet invited"), (RESPONSE_INVITED, "Invited"), (RESPONSE_REINVITED, "Reinvited"), (RESPONSE_MULTIPLY_REINVITED, "Multiply reinvited"), (RESPONSE_UNRESPONSIVE, "Unresponsive"), (RESPONSE_ACCEPTED, "Accepted, for immediate start"), (RESPONSE_POSTPONED, "Accepted, but start date postponed"), (RESPONSE_DECLINED, "Declined"), ) response = models.CharField(max_length=16, choices=RESPONSE_CHOICES, blank=True) postpone_start_to = models.DateField(blank=True) comments = models.TextField( help_text=( "You can use plain text, Markdown or reStructuredText; see our " '<a href="/markup/help/" target="_blank">markup help</a> pages.' ), blank=True, ) class Meta: ordering = [ "nomination", ] verbose_name_plural = "Fellowship Invitations" def __str__(self): return f"Invitation for {self.nomination}" @property def declined(self): return self.response == self.RESPONSE_DECLINED