SciPost Code Repository

Skip to content
Snippets Groups Projects
models.py 6.21 KiB
Newer Older
__copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"


from django.core.urlresolvers import reverse
from django.db.models.functions import Concat
from django.shortcuts import get_object_or_404

from scipost.behaviors import orcid_validator
from scipost.constants import (
    TITLE_CHOICES, SCIPOST_DISCIPLINES, DISCIPLINE_PHYSICS, SCIPOST_SUBJECT_AREAS)
from scipost.fields import ChoiceArrayField
from scipost.models import Contributor
from comments.models import Comment
from journals.models import Publication, PublicationAuthorsTable
from ontology.models import Topic
from theses.models import ThesisLink
from .constants import PROFILE_NON_DUPLICATE_REASONS
from .managers import ProfileQuerySet

    A Profile object instance contains information about an individual.

    This individual is a potential SciPost Contributor but is not necessarily registered.
    It is created and used by Admin, EdAdmin or other internal SciPost staff.

    For registered Contributors, a profile is initially created from the contributor-filled
    information in the Contributor object. Profile should thus be viewed as containing
    the Admin-certified version of this information.

    The information is only partial, and is meant to be used among others to:

    #. help with editorial matters:
       #. help EdAdmin identify prospective Fellows
       #. help Fellows identify appropriate referees
       #. mark potential conflicts of interest

    #. allow respecting people's preferences:
       #. mark somebody as not willing to receive emails from SciPost.
       #. mark somebody as a non-referee (if that person does not want to referee for SciPost)
    """
    title = models.CharField(max_length=4, choices=TITLE_CHOICES, blank=True, null=True)
    first_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)
    discipline = models.CharField(max_length=20, choices=SCIPOST_DISCIPLINES,
                                  default=DISCIPLINE_PHYSICS, verbose_name='Main discipline')
    expertises = ChoiceArrayField(
        models.CharField(max_length=10, choices=SCIPOST_SUBJECT_AREAS),
        blank=True, null=True)
    orcid_id = models.CharField(max_length=20, verbose_name="ORCID id",
                                blank=True, validators=[orcid_validator])
    webpage = models.URLField(blank=True)
    # Topics for semantic linking
    topics = models.ManyToManyField('ontology.Topic', blank=True)

    # Preferences for interactions with SciPost:
    accepts_SciPost_emails = models.BooleanField(default=True)
    accepts_refereeing_requests = models.BooleanField(default=True)

    objects = ProfileQuerySet.as_manager()

    class Meta:
        ordering = ['last_name']

    def __str__(self):
        return '%s, %s %s' % (self.last_name,
                              self.get_title_display() if self.title != None else '',
                              self.first_name)
    @property
    def email(self):
Jorran de Wit's avatar
Jorran de Wit committed
        return getattr(self.emails.filter(primary=True).first(), 'email', '')
    def has_active_contributor(self):
        has_active_contributor = False
            has_active_contributor = (self.contributor is not None and
                                      self.contributor.is_active)
        except Contributor.DoesNotExist:
            pass
        return has_active_contributor
    def get_absolute_url(self):
        return reverse('profiles:profile_detail', kwargs={'pk': self.id})

    def publications(self):
        """
        Returns all the publications associated to this Profile.
        """
        return Publication.objects.published().filter(
            models.Q(authors__unregistered_author__profile=self) |
            models.Q(authors__contributor__profile=self))

    def comments(self):
        """
        Returns all the Comments associated to this Profile.
        """
        return Comment.objects.filter(author__profile=self)

    def theses(self):
        """
        Returns all the Theses associated to this Profile.
        """
        return ThesisLink.objects.filter(author_as_cont__profile=self)


class ProfileEmail(models.Model):
    """Any email related to a Profile instance."""
    profile = models.ForeignKey('profiles.Profile', on_delete=models.CASCADE)
    email = models.EmailField()
    still_valid = models.BooleanField(default=True)
    primary = models.BooleanField(default=False)

    class Meta:
        unique_together = ['profile', 'email']
        ordering = ['-primary', '-still_valid', 'email']
Jorran de Wit's avatar
Jorran de Wit committed
        default_related_name = 'emails'
Jorran de Wit's avatar
Jorran de Wit committed

    def __str__(self):
        return self.email


def get_profiles(slug):
    """
    Returns a list of Profiles for which there exists at least one
    Publication/Submission object carrying this Topic.
    """
    topic = get_object_or_404(Topic, slug=slug)
    publications = PublicationAuthorsTable.objects.filter(publication__topics__in=[topic,])
    cont_id_list = [tbl.contributor.id for tbl in publications.all() \
                    if tbl.contributor is not None]
    unreg_id_list = [tbl.unregistered_author.id for tbl in publications.all() \
                     if tbl.unregistered_author is not None]
    return Profile.objects.filter(models.Q(contributor__id__in=cont_id_list) |
                                  models.Q(unregisteredauthor__id__in=unreg_id_list
Jean-Sébastien Caux's avatar
Jean-Sébastien Caux committed
                                  )).distinct()


class ProfileNonDuplicates(models.Model):
    """
    Sets of Profiles which are not duplicates of each other,
    and thus can be filtered out of any dynamically generated list of potential duplicates.
    """
    profiles = models.ManyToManyField('profiles.Profile')
    reason = models.CharField(max_length=32, choices=PROFILE_NON_DUPLICATE_REASONS)
    class Meta:
        verbose_name = 'Profile non-duplicates'
        verbose_name_plural = 'Profile non-duplicates'

    def __str__(self):
        return '%s, %s (%i)' % (self.profiles.first().last_name,
                                self.profiles.first().first_name,
                                self.profiles.count())

    @property
    def full_name(self):
        return '%s%s' % (self.profiles.first().last_name, self.profiles.first().first_name)