Source code for scipost.managers

__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"


from django.db import models
from django.db.models import Count, Q
from django.db.models.functions import Concat, Lower
from django.utils import timezone

from .constants import NORMAL_CONTRIBUTOR, NEWLY_REGISTERED, DOUBLE_ACCOUNT, AUTHORSHIP_CLAIM_PENDING


[docs]class FellowManager(models.Manager): """Custom defined filters for the Fellow model."""
[docs] def active(self): """Filter Fellows active within its set date ranges.""" today = timezone.now().date() return self.filter( Q(start_date__lte=today, until_date__isnull=True) | Q(start_date__isnull=True, until_date__gte=today) | Q(start_date__lte=today, until_date__gte=today) | Q(start_date__isnull=True, until_date__isnull=True) ).order_by('contributor__user__last_name')
[docs]class ContributorQuerySet(models.QuerySet): """Custom defined filters for the Contributor model."""
[docs] def active(self): """Return all validated and vetted Contributors.""" return self.filter(user__is_active=True, status=NORMAL_CONTRIBUTOR)
[docs] def nonduplicates(self): """ Filter out duplicate Contributors. """ return self.exclude(duplicate_of__isnull=False)
[docs] def available(self): """Filter out the Contributors that have active unavailability periods.""" today = timezone.now().date() return self.exclude( unavailability_periods__start__lte=today, unavailability_periods__end__gte=today)
[docs] def awaiting_validation(self): """Filter Contributors that have not been validated by the user.""" return self.filter(user__is_active=False, status=NEWLY_REGISTERED)
[docs] def awaiting_vetting(self): """Filter Contributors that have not been vetted through.""" return self.filter(user__is_active=True, status=NEWLY_REGISTERED ).exclude(status=DOUBLE_ACCOUNT)
[docs] def fellows(self): """TODO: NEEDS UPDATE TO NEW FELLOWSHIP RELATIONS.""" return self.filter(fellowships__isnull=False).distinct()
[docs] def specialties_overlap(self, discipline, expertises=[]): """ Returns all Contributors specialized in the given discipline and any of the (optional) expertises. This method is also separately implemented for Profile and Fellowship objects. """ qs = self.filter(profile__discipline=discipline) if expertises and len(expertises) > 0: qs = qs.filter(profile__expertises__overlap=expertises) return qs
[docs] def specialties_contain(self, discipline, expertises=[]): """ Returns all Contributors specialized in the given discipline and all of the (optional) expertises. This method is also separately implemented for Profile and Fellowship objects. """ qs = self.filter(profile__discipline=discipline) if expertises and len(expertises) > 0: qs = qs.filter(profile__expertises__contains=expertises) return qs
[docs] def with_duplicate_names(self): """ Returns only potential duplicate Contributors (as identified by first and last names). Admins and superusers are explicitly excluded. """ contribs = self.exclude(status=DOUBLE_ACCOUNT ).exclude(user__is_superuser=True).exclude(user__is_staff=True ).annotate(full_name=Concat('user__last_name', 'user__first_name')) duplicates = contribs.values('full_name').annotate( nr_count=Count('full_name')).filter(nr_count__gt=1).values_list('full_name', flat=True) return contribs.filter( full_name__in=duplicates).order_by('user__last_name', 'user__first_name', '-id')
[docs] def with_duplicate_email(self): """ Return Contributors having duplicate emails. """ qs = self.exclude(status=DOUBLE_ACCOUNT ).exclude(user__is_superuser=True).exclude( user__is_staff=True).annotate(lower_email=Lower('user__email')) duplicates = qs.values('lower_email').annotate( Count('id')).filter(id__count__gt=1).values_list('lower_email', flat=True) return qs.filter(user__email__in=duplicates)
[docs]class UnavailabilityPeriodManager(models.Manager):
[docs] def today(self): today = timezone.now().date() return self.filter(start__lte=today, end__gte=today)
[docs] def future(self): today = timezone.now().date() return self.filter(end__gte=today)
[docs]class AuthorshipClaimQuerySet(models.QuerySet):
[docs] def awaiting_vetting(self): return self.filter(status=AUTHORSHIP_CLAIM_PENDING)