<commit_before>import tablib
import logging
from tablib.compat import csv, StringIO

from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache
from django.contrib.auth import models as auth_models
from django.db.models import Q

from pyconde.conference import models as conference_models
from pyconde.accounts import utils as account_utils


logger = logging.getLogger(__name__)


def can_review_proposal(user, proposal=None, reset_cache=False):
    cache_key = 'reviewer_pks'
    reviewer_pks = cache.get(cache_key)
    if user.is_anonymous() or not hasattr(user, 'pk'):
        return False
    if reset_cache or reviewer_pks is None:
        perm = auth_models.Permission.objects.get(codename='add_review')
        reviewer_pks = set(u['pk'] for u in auth_models.User.objects.filter(Q(is_superuser=True) | Q(user_permissions=perm) | Q(groups__permissions=perm)).values('pk'))
        cache.set(cache_key, reviewer_pks)
        logger.debug("reviewer_pks cache has been rebuilt")
    return user.pk in reviewer_pks


def can_participate_in_review(user, proposal):
    if can_review_proposal(user, proposal):
        return True
    if is_proposal_author(user, proposal):
        return True
    return False


def is_proposal_author(user, proposal):
    if not hasattr(user, 'speaker_profile'):
        return False
    if user.speaker_profile == proposal.speaker or user.speaker_profile in proposal.additional_speakers.all():
        return True
    return False


def merge_comments_and_versions(comments, versions):
    def _comparator(a, b):
        return cmp(a.pub_date, b.pub_date)
    return sorted(list(comments) + list(versions), cmp=_comparator)


def get_people_to_notify(proposal, current_user=None):
    """
    Generates a set of all users that are somehow related to the given proposal.
    If a current_user is specified, this user will NOT be included in this set.
    """
    people_to_notify = set()
    people_to_notify.update([u.author for u in proposal.comments.select_related('author')])
    people_to_notify.update([review.user for review in proposal.reviews.all().select_related('user')])
    people_to_notify.add(proposal.speaker.user)
    people_to_notify.update([s.user for s in proposal.additional_speakers.all()])
    if current_user:
        people_to_notify.remove(current_user)
    return people_to_notify


def send_comment_notification(comment, notify_author=False):
    """
    Send a comment notification mail to all users related to the comment's
    proposal except for the author of the comment unless notify_author=True
    is passed.
    """
    proposal = comment.proposal
    current_user = comment.author
    if notify_author:
        current_user = None
    hide_author = conference_models.current_conference().anonymize_proposal_author and\
        is_proposal_author(comment.author, proposal)
    body = render_to_string('reviews/emails/comment_notification.txt', {
        'comment': comment,
        'proposal': proposal,
        'hide_author': hide_author,
        'site': Site.objects.get_current(),
        'proposal_url': reverse('reviews-proposal-details', kwargs={'pk': proposal.pk}),
    })
    if hide_author:
        subject = _("[REVIEW] The author has commented on \"%(title)s\"")
    else:
        subject = _("[REVIEW] %(author)s commented on \"%(title)s\"")
    msg = EmailMessage(subject=subject % {
            'author': account_utils.get_account_name(comment.author),
            'title': proposal.title},
        bcc=[u.email for u in get_people_to_notify(proposal, current_user)],
        body=body)
    msg.send()


def send_proposal_update_notification(version, notify_author=False):
    """
    Send a version notification mail to all users related to the version's
    proposal except for the author of the version unless notify_author=True
    is passed.
    """
    proposal = version.original
    current_user = version.creator
    if notify_author:<commit_msg>added very basic recipient check - fixes Issue #162 (Server Error beim Posten eines Reviewer-Kommentars)<commit_after>import tablib
import logging
from tablib.compat import csv, StringIO
import re

from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache
from django.contrib.auth import models as auth_models
from django.db.models import Q

from pyconde.conference import models as conference_models
from pyconde.accounts import utils as account_utils

EMAIL_REGEX = re.compile(r"[^@]+@[^@]+\.[^@]+")

logger = logging.getLogger(__name__)


def can_review_proposal(user, proposal=None, reset_cache=False):
    cache_key = 'reviewer_pks'
    reviewer_pks = cache.get(cache_key)
    if user.is_anonymous() or not hasattr(user, 'pk'):
        return False
    if reset_cache or reviewer_pks is None:
        perm = auth_models.Permission.objects.get(codename='add_review')
        reviewer_pks = set(u['pk'] for u in auth_models.User.objects.filter(Q(is_superuser=True) | Q(user_permissions=perm) | Q(groups__permissions=perm)).values('pk'))
        cache.set(cache_key, reviewer_pks)
        logger.debug("reviewer_pks cache has been rebuilt")
    return user.pk in reviewer_pks


def can_participate_in_review(user, proposal):
    if can_review_proposal(user, proposal):
        return True
    if is_proposal_author(user, proposal):
        return True
    return False

def has_valid_mailaddr(user):
    mail = user.email
    return mail and EMAIL_REGEX.match(mail)

def is_proposal_author(user, proposal):
    if not hasattr(user, 'speaker_profile'):
        return False
    if user.speaker_profile == proposal.speaker or user.speaker_profile in proposal.additional_speakers.all():
        return True
    return False


def merge_comments_and_versions(comments, versions):
    def _comparator(a, b):
        return cmp(a.pub_date, b.pub_date)
    return sorted(list(comments) + list(versions), cmp=_comparator)


def get_people_to_notify(proposal, current_user=None):
    """
    Generates a set of all users that are somehow related to the given proposal.
    If a current_user is specified, this user will NOT be included in this set.
    """
    people_to_notify = set()
    people_to_notify.update([u.author for u in proposal.comments.select_related('author')])
    people_to_notify.update([review.user for review in proposal.reviews.all().select_related('user')])
    people_to_notify.add(proposal.speaker.user)
    people_to_notify.update([s.user for s in proposal.additional_speakers.all()])
    if current_user:
        people_to_notify.remove(current_user)
    return people_to_notify


def send_comment_notification(comment, notify_author=False):
    """
    Send a comment notification mail to all users related to the comment's
    proposal except for the author of the comment unless notify_author=True
    is passed.
    """
    proposal = comment.proposal
    current_user = comment.author
    if notify_author:
        current_user = None
    hide_author = conference_models.current_conference().anonymize_proposal_author and\
        is_proposal_author(comment.author, proposal)
    body = render_to_string('reviews/emails/comment_notification.txt', {
        'comment': comment,
        'proposal': proposal,
        'hide_author': hide_author,
        'site': Site.objects.get_current(),
        'proposal_url': reverse('reviews-proposal-details', kwargs={'pk': proposal.pk}),
    })
    if hide_author:
        subject = _("[REVIEW] The author has commented on \"%(title)s\"")
    else:
        subject = _("[REVIEW] %(author)s commented on \"%(title)s\"")
    msg = EmailMessage(subject=subject % {
            'author': account_utils.get_account_name(comment.author),
            'title': proposal.title},
        bcc=[u.email for u in get_people_to_notify(proposal, current_user)
             if has_valid_mailaddr(u)],
        body=body)
    msg.send()


def send_proposal_update_notification(version, notify_author=False):
    """
    Send a version notification mail to all users related to the version's
    proposal except for the author of the version unless notify_author=True
    is passed.
    """
    proposal = version.original
    current_user = version.creator
    if notify_author:
{'fraction_non_alphanumeric': 0.09268519595301779, 'fraction_numerical': 0.0003488777764856379, 'mean_word_length': 3.9283667621776504, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4478333', 'n_tokens_mistral': 2558, 'n_tokens_neox': 2542, 'n_words': 668}