def _compute_queue(reviewer: User): days = settings.IOTD_REVIEW_WINDOW_DAYS cutoff = datetime.now() - timedelta(days) return Image.objects.annotate( num_submissions=Count('iotdsubmission', distinct=True), num_dismissals=Count('iotddismissedimage', distinct=True), last_submission_timestamp=Subquery(IotdSubmission.last_for_image(OuterRef('pk')).values('date')) ).filter( Q(deleted__isnull=True) & Q(last_submission_timestamp__gte=cutoff) & Q(designated_iotd_reviewers=reviewer) & Q(num_submissions__gte=settings.IOTD_SUBMISSION_MIN_PROMOTIONS) & Q(num_dismissals__lt=settings.IOTD_MAX_DISMISSALS) & Q( Q(iotd__isnull=True) | Q(iotd__date__gt=datetime.now().date()) ) ).exclude( Q(iotdsubmission__submitter=reviewer) | Q(user=reviewer) | Q(iotddismissedimage__user=reviewer) | Q( Q(iotdvote__reviewer=reviewer) & Q(iotdvote__date__lt=DateTimeService.today()) ) )
def may_toggle_vote_image(user, image): if user.is_superuser: return True, None if not user.groups.filter(name='iotd_reviewers').exists(): return False, _("You are not a member of the IOTD Reviewers board.") if user == image.user: return False, _("You cannot vote for your own image.") if image.is_wip: return False, _("Images in the staging area cannot be voted for.") 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 vote for a judge's image.") # Import here to avoid circular dependency from astrobin_apps_iotd.models import IotdSubmission, IotdVote, Iotd if not IotdSubmission.objects.filter(image=image).exists(): return False, _( "You cannot vote for an image that has not been submitted.") if user.pk in IotdSubmission.objects.filter(image=image).values_list( 'submitter', flat=True): return False, _("You cannot vote for your own submission.") 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_REVIEW_WINDOW_DAYS if IotdSubmission.first_for_image( image).date < datetime.now() - timedelta(days): return False, _( "You cannot vote for an image that has been in the submission queue for more than %(max_days)s days." ) % { 'max_days': days } max_allowed = settings.IOTD_REVIEW_MAX_PER_DAY reviewed_today = IotdVote.objects.filter( reviewer=user, date__contains=datetime.now().date()).count() toggling_on = not IotdVote.objects.filter(reviewer=user, image=image).exists() if reviewed_today >= max_allowed and toggling_on: return False, _( "You have already voted for %(max_allowed)s images today.") % { 'max_allowed': max_allowed } return True, None
def to_representation(self, instance: Image): representation = super().to_representation(instance) last_submission: QuerySet[ IotdSubmission] = IotdSubmission.last_for_image(instance.pk) if last_submission: representation.update({ 'last_submission_timestamp': last_submission[0].date if last_submission.exists() else None }) return representation
def may_toggle_vote_image(user, image): if user.is_superuser: return True, None if not user.groups.filter(name = 'iotd_reviewers').exists(): return False, _("You are not a member of the IOTD Reviewers board.") if user == image.user: return False, _("You cannot vote for your own image.") if image.is_wip: return False, _("Images in the staging area cannot be voted for.") 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 vote for a judge's image.") # Import here to avoid circular dependency from astrobin_apps_iotd.models import IotdSubmission, IotdVote, Iotd if not IotdSubmission.objects.filter(image = image).exists(): return False, _("You cannot vote for an image that has not been submitted.") if user.pk in IotdSubmission.objects.filter(image = image).values_list('submitter', flat = True): return False, _("You cannot vote for your own submission.") 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_REVIEW_WINDOW_DAYS if IotdSubmission.first_for_image(image).date < datetime.now() - timedelta(days): return False, _("You cannot vote for an image that has been in the submission queue for more than %(max_days)s days.") % { 'max_days': days } max_allowed = settings.IOTD_REVIEW_MAX_PER_DAY reviewed_today = IotdVote.objects.filter( reviewer = user, date__contains = datetime.now().date()).count() toggling_on = not IotdVote.objects.filter(reviewer = user, image = image).exists() if reviewed_today >= max_allowed and toggling_on: return False, _("You have already voted for %(max_allowed)s images today.") % { 'max_allowed': max_allowed } return True, None
def update_review_queues(self): def _compute_queue(reviewer: User): days = settings.IOTD_REVIEW_WINDOW_DAYS cutoff = datetime.now() - timedelta(days) return Image.objects.annotate( num_submissions=Count('iotdsubmission', distinct=True), num_dismissals=Count('iotddismissedimage', distinct=True), last_submission_timestamp=Subquery(IotdSubmission.last_for_image(OuterRef('pk')).values('date')) ).filter( Q(deleted__isnull=True) & Q(last_submission_timestamp__gte=cutoff) & Q(designated_iotd_reviewers=reviewer) & Q(num_submissions__gte=settings.IOTD_SUBMISSION_MIN_PROMOTIONS) & Q(num_dismissals__lt=settings.IOTD_MAX_DISMISSALS) & Q( Q(iotd__isnull=True) | Q(iotd__date__gt=datetime.now().date()) ) ).exclude( Q(iotdsubmission__submitter=reviewer) | Q(user=reviewer) | Q(iotddismissedimage__user=reviewer) | Q( Q(iotdvote__reviewer=reviewer) & Q(iotdvote__date__lt=DateTimeService.today()) ) ) for reviewer in User.objects.filter(groups__name='iotd_reviewers'): IotdReviewQueueEntry.objects.filter(reviewer=reviewer).delete() for image in _compute_queue(reviewer).iterator(): last_submission = IotdSubmission.last_for_image(image.pk).first() IotdReviewQueueEntry.objects.create( reviewer=reviewer, image=image, last_submission_timestamp=last_submission.date )
def may_toggle_vote_image(user, image): if not user.groups.filter(name='iotd_reviewers').exists(): return False, _("You are not a member of the IOTD Reviewers board.") if user == image.user: return False, _("You cannot vote for your own image.") if image.is_wip: return False, _("Images in the staging area cannot be voted for.") 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, user=user).exists(): return False, _( "You cannot vote for an image that you already dismissed.") if IotdDismissedImage.objects.filter( image=image).count() >= settings.IOTD_MAX_DISMISSALS: return False, _( "You cannot vote for an image that has been dismissed by %(number)s members of the IOTD Staff." ) % { 'number': settings.IOTD_MAX_DISMISSALS } # Import here to avoid circular dependency from astrobin_apps_iotd.models import IotdSubmission, IotdVote, Iotd if not IotdSubmission.objects.filter(image=image).exists(): return False, _( "You cannot vote for an image that has not been submitted.") if user.pk in IotdSubmission.objects.filter(image=image).values_list( 'submitter', flat=True): return False, _("You cannot vote for your own submission.") if Iotd.objects.filter(image=image, date__lte=datetime.now().date()).exists(): return False, _("This image has already been an IOTD in the past") if IotdSubmission.objects.filter( image=image).count() < settings.IOTD_SUBMISSION_MIN_PROMOTIONS: return False, _( "You cannot vote for an image that has not been submitted at least %(num)s times." % {'num': settings.IOTD_SUBMISSION_MIN_PROMOTIONS}) days = settings.IOTD_REVIEW_WINDOW_DAYS if IotdSubmission.last_for_image( image.pk)[0].date < datetime.now() - timedelta(days): return False, _( "You cannot vote for an image that has been in the review queue for more than %(max_days)s day(s)." ) % { 'max_days': days } max_allowed = settings.IOTD_REVIEW_MAX_PER_DAY reviewed_today = IotdVote.objects.filter( reviewer=user, date__contains=datetime.now().date()).count() toggling_on = not IotdVote.objects.filter(reviewer=user, image=image).exists() if reviewed_today >= max_allowed and toggling_on: return False, _( "You have already voted for %(max_allowed)s image(s) today.") % { 'max_allowed': max_allowed } if settings.PREMIUM_RESTRICTS_IOTD: if is_free(image.user): return False, _( "Users with a Free membership cannot participate in the IOTD.") return True, None