def update_judgement_queues(self): def _compute_queue(judge: User): days = settings.IOTD_JUDGEMENT_WINDOW_DAYS cutoff = datetime.now() - timedelta(days) return Image.objects.annotate( num_votes=Count('iotdvote', distinct=True), num_dismissals=Count('iotddismissedimage', distinct=True), last_vote_timestamp=Subquery(IotdVote.last_for_image(OuterRef('pk')).values('date')) ).filter( Q(deleted__isnull=True) & Q(last_vote_timestamp__gte=cutoff) & Q(num_votes__gte=settings.IOTD_REVIEW_MIN_PROMOTIONS) & Q(num_dismissals__lt=settings.IOTD_MAX_DISMISSALS) & Q( Q(iotd__isnull=True) | Q(iotd__date__gt=datetime.now().date()) ) ).exclude( Q(iotdvote__reviewer=judge) | Q(iotddismissedimage__user=judge) | Q(user=judge) ) for judge in User.objects.filter(groups__name='iotd_judges'): IotdJudgementQueueEntry.objects.filter(judge=judge).delete() for image in _compute_queue(judge).iterator(): last_vote = IotdVote.last_for_image(image.pk).first() IotdJudgementQueueEntry.objects.create( judge=judge, image=image, last_vote_timestamp=last_vote.date )
def to_representation(self, instance: Image): representation = super().to_representation(instance) last_vote: QuerySet[IotdVote] = IotdVote.last_for_image(instance.pk) if last_vote: representation.update( { 'last_vote_timestamp': last_vote[0].date if last_vote.exists() else None } ) return representation
def _compute_queue(judge: User): days = settings.IOTD_JUDGEMENT_WINDOW_DAYS cutoff = datetime.now() - timedelta(days) return Image.objects.annotate( num_votes=Count('iotdvote', distinct=True), num_dismissals=Count('iotddismissedimage', distinct=True), last_vote_timestamp=Subquery(IotdVote.last_for_image(OuterRef('pk')).values('date')) ).filter( Q(deleted__isnull=True) & Q(last_vote_timestamp__gte=cutoff) & Q(num_votes__gte=settings.IOTD_REVIEW_MIN_PROMOTIONS) & Q(num_dismissals__lt=settings.IOTD_MAX_DISMISSALS) & Q( Q(iotd__isnull=True) | Q(iotd__date__gt=datetime.now().date()) ) ).exclude( Q(iotdvote__reviewer=judge) | Q(iotddismissedimage__user=judge) | Q(user=judge) )
def may_elect_iotd(user, image): if not user.groups.filter(name='iotd_judges').exists(): return False, _("You are not a member of the IOTD Judges board.") if user == image.user: return False, _("You cannot elect your own image.") if image.is_wip: return False, _("Images in the staging area cannot be elected.") if image.user.userprofile.exclude_from_competitions: return False, _( "This user has chosen to be excluded from competitions.") if image.user.userprofile.banned_from_competitions: return False, _("This user has been banned from competitions.") from astrobin_apps_iotd.models import IotdDismissedImage if IotdDismissedImage.objects.filter( image=image).count() >= settings.IOTD_MAX_DISMISSALS: return False, _( "You cannot submit an image that has been dismissed by %(number)s member(s) of the IOTD Staff." ) % { 'number': settings.IOTD_MAX_DISMISSALS } if settings.PREMIUM_RESTRICTS_IOTD: if is_free(image.user): return False, _( "Users with a Free membership cannot participate in the IOTD.") # Import here to avoid circular dependency from astrobin_apps_iotd.models import IotdSubmission, IotdVote, Iotd if not IotdVote.objects.filter(image=image).exists(): return False, _("You cannot elect an image that has not been voted.") if user.pk in IotdSubmission.objects.filter(image=image).values_list( 'submitter', flat=True): return False, _("You cannot elect your own submission.") if user.pk in IotdVote.objects.filter(image=image).values_list('reviewer', flat=True): return False, _("You cannot elect an image you voted for.") if Iotd.objects.filter(image=image, date__lte=datetime.now().date()).exists(): return False, _("This image has already been an IOTD in the past") days = settings.IOTD_JUDGEMENT_WINDOW_DAYS if IotdVote.last_for_image( image.pk)[0].date < datetime.now() - timedelta(days): return False, _( "You cannot elect an image that has been in the review queue for more than %(max_days)s day(s)." ) % { 'max_days': days } max_allowed = settings.IOTD_JUDGEMENT_MAX_PER_DAY judged_today = Iotd.objects.filter( judge=user, created__contains=datetime.now().date()).count() toggling_on = not Iotd.objects.filter(image=image).exists() if judged_today >= max_allowed and toggling_on: return False, _( "You have already elected %(max_allowed)s image(s) today.") % { 'max_allowed': max_allowed } max_allowed = settings.IOTD_JUDGEMENT_MAX_FUTURE_PER_JUDGE scheduled = Iotd.objects.filter(judge=user, date__gt=datetime.now().date()).count() toggling_on = not Iotd.objects.filter(image=image).exists() if scheduled >= max_allowed and toggling_on: return False, _( "You have already scheduled %(max_allowed)s IOTD(s).") % { 'max_allowed': max_allowed } if IotdVote.objects.filter( image=image).count() < settings.IOTD_REVIEW_MIN_PROMOTIONS: return False, _( "You cannot elect for an image that has not been voted at least %(num)s times." % {'num': settings.IOTD_REVIEW_MIN_PROMOTIONS}) return True, None
def may_elect_iotd(user, image): if user.is_superuser: return True, None if not user.groups.filter(name = 'iotd_judges').exists(): return False, _("You are not a member of the IOTD Judges board.") if user == image.user: return False, _("You cannot elect your own image.") if image.is_wip: return False, _("Images in the staging area cannot be elected.") if image.user.userprofile.exclude_from_competitions: return False, _("This user has chosen to be excluded from competitions.") if image.user in Group.objects.get(name = 'iotd_judges').user_set.all(): return False, _("You cannot elect a judge's image.") # Import here to avoid circular dependency from astrobin_apps_iotd.models import IotdSubmission, IotdVote, Iotd if not IotdVote.objects.filter(image = image).exists(): return False, _("You cannot elect an image that has not been voted.") if user.pk in IotdSubmission.objects.filter(image = image).values_list('submitter', flat = True): return False, _("You cannot elect your own submission.") if user.pk in IotdVote.objects.filter(image = image).values_list('reviewer', flat = True): return False, _("You cannot elect an image you voted for.") if Iotd.objects.filter(image = image, date__lte = datetime.now().date()).exists(): return False, _("This image has already been an IOTD in the past") days = settings.IOTD_JUDGEMENT_WINDOW_DAYS if IotdVote.first_for_image(image).date < datetime.now() - timedelta(days): return False, _("You cannot elect an image that has been in the review queue for more than %(max_days)s days.") % { 'max_days': days } max_allowed = settings.IOTD_JUDGEMENT_MAX_PER_DAY judged_today = Iotd.objects.filter( judge = user, created__contains = datetime.now().date()).count() toggling_on = not Iotd.objects.filter(image = image).exists() if judged_today >= max_allowed and toggling_on: return False, _("You have already elected %(max_allowed)s images today.") % { 'max_allowed': max_allowed } max_allowed = settings.IOTD_JUDGEMENT_MAX_FUTURE_PER_JUDGE scheduled = Iotd.objects.filter( judge = user, date__gt = datetime.now().date()).count() toggling_on = not Iotd.objects.filter(image = image).exists() if scheduled >= max_allowed and toggling_on: return False, _("You have already scheduled %(max_allowed)s IOTDs.") % { 'max_allowed': max_allowed } return True, None
def may_elect_iotd(user, image): if user.is_superuser: return True, None if not user.groups.filter(name='iotd_judges').exists(): return False, _("You are not a member of the IOTD Judges board.") if user == image.user: return False, _("You cannot elect your own image.") if image.is_wip: return False, _("Images in the staging area cannot be elected.") if image.user.userprofile.exclude_from_competitions: return False, _( "This user has chosen to be excluded from competitions.") if image.user in Group.objects.get(name='iotd_judges').user_set.all(): return False, _("You cannot elect a judge's image.") # Import here to avoid circular dependency from astrobin_apps_iotd.models import IotdSubmission, IotdVote, Iotd if not IotdVote.objects.filter(image=image).exists(): return False, _("You cannot elect an image that has not been voted.") if user.pk in IotdSubmission.objects.filter(image=image).values_list( 'submitter', flat=True): return False, _("You cannot elect your own submission.") if user.pk in IotdVote.objects.filter(image=image).values_list('reviewer', flat=True): return False, _("You cannot elect an image you voted for.") if Iotd.objects.filter(image=image, date__lte=datetime.now().date()).exists(): return False, _("This image has already been an IOTD in the past") days = settings.IOTD_JUDGEMENT_WINDOW_DAYS if IotdVote.first_for_image(image).date < datetime.now() - timedelta(days): return False, _( "You cannot elect an image that has been in the review queue for more than %(max_days)s days." ) % { 'max_days': days } max_allowed = settings.IOTD_JUDGEMENT_MAX_PER_DAY judged_today = Iotd.objects.filter( judge=user, created__contains=datetime.now().date()).count() toggling_on = not Iotd.objects.filter(image=image).exists() if judged_today >= max_allowed and toggling_on: return False, _( "You have already elected %(max_allowed)s images today.") % { 'max_allowed': max_allowed } max_allowed = settings.IOTD_JUDGEMENT_MAX_FUTURE_PER_JUDGE scheduled = Iotd.objects.filter(judge=user, date__gt=datetime.now().date()).count() toggling_on = not Iotd.objects.filter(image=image).exists() if scheduled >= max_allowed and toggling_on: return False, _( "You have already scheduled %(max_allowed)s IOTDs.") % { 'max_allowed': max_allowed } return True, None