<commit_before>import datetime
import logging

import pytz
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.db.models.aggregates import Count, Sum
from django.db.models.signals import post_init, post_save, pre_save
from django.dispatch import receiver
from django.template.defaultfilters import slugify
from django.utils import timezone
from django.utils.functional import lazy
from django.utils.http import urlquote
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django_extensions.db.fields import ModificationDateTimeField, CreationDateTimeField
from moneyed.classes import Money
from select_multiple_field.models import SelectMultipleField

from bluebottle.analytics.tasks import queue_analytics_record
from bluebottle.bb_metrics.utils import bb_track
from bluebottle.bb_projects.models import (
    BaseProject, ProjectPhase, BaseProjectDocument
)
from bluebottle.clients import properties
from bluebottle.clients.utils import LocalTenant
from bluebottle.tasks.models import Task, TaskMember
from bluebottle.utils.exchange_rates import convert
from bluebottle.utils.fields import MoneyField, get_currency_choices, get_default_currency
from bluebottle.utils.utils import StatusDefinition, PreviousStatusMixin
from bluebottle.wallposts.models import (
    MediaWallpostPhoto, MediaWallpost, TextWallpost
)
from .mails import (
    mail_project_funded_internal, mail_project_complete,
    mail_project_incomplete
)
from .signals import project_funded


logger = logging.getLogger(__name__)


class ProjectPhaseLog(models.Model):
    project = models.ForeignKey('projects.Project')
    status = models.ForeignKey('bb_projects.ProjectPhase')
    start = CreationDateTimeField(
        _('created'), help_text=_('When this project entered in this status.')
    )

    class Analytics:
        type = 'project'
        tags = {
            'id': 'project.id',
            'sub_type': 'project.project_type',
            'status': 'status.name',
            'status_slug': 'status.slug',
            'theme': {
                'project.theme.name': {'translate': True}
            },
            'theme_slug': 'project.theme.slug',
            'location': 'project.location.name',
            'location_group': 'project.location.group.name',
            'country': 'project.country_name'
        }
        fields = {
            'id': 'project.id',
            'user_id': 'project.owner.id'
        }

        @staticmethod
        def timestamp(obj, created):
            return obj.start


class ProjectDocument(BaseProjectDocument):
    @property
    def document_url(self):
        # pk may be unset if not saved yet, in which case no url can be
        # generated.
        if self.pk is not None:
            return reverse('project-document-file', kwargs={'pk': self.pk})
        return None

    @property
    def owner(self):
        return self.project.owner

    @property
    def parent(self):
        return self.project


class Project(BaseProject, PreviousStatusMixin):
    latitude = models.DecimalField(
        _('latitude'), max_digits=21, decimal_places=18, null=True, blank=True)
    longitude = models.DecimalField(
        _('longitude'), max_digits=21, decimal_places=18, null=True, blank=True)

    reach = models.PositiveIntegerField(
        _('Reach'), help_text=_('How many people do you expect to reach?'),
        blank=True, null=True)

    video_url = models.URLField(
        _('video'), max_length=100, blank=True, null=True, default='',
        help_text=_("Do you have a video pitch or a short movie that "
                    "explains your project? Cool! We can't wait to see it! "
                    "You can paste the link to YouTube or Vimeo video here"))

    popularity = models.FloatField(null=False, default=0)
    is_campaign = models.BooleanField(verbose_name='On homepage', default=False, help_text=_(
        "Project is part of a campaign and gets special promotion."))

    skip_monthly = models.BooleanField(_("Skip monthly"),
                                       help_text=_(
                                           "Skip this project when running monthly donations"),
                                       default=False)

    allow_overfunding = models.BooleanField(default=True)
    story = models.TextField(
        _("story"), help_text=_("This is the help text for the story field"),
        blank=True, null=True)

    # TODO: Remove these fields?
    effects = models.TextField(
        _("effects"), blank=True, null=True,
        help_text=_("What will be the Impact? How will your "
                    "Smart Idea change the lives of people?"))
    for_who = models.TextField(
        _("for who"), blank=True, null=True,
        help_text=_("Describe your target group"))
    future = models.TextField(
        _("future"), blank=True, null=True,
        help_text=_("How will this project be self-sufficient and "
                    "sustainable in the long term?"))

    date_submitted = models.DateTimeField(_('Campaign Submitted'), null=True,
                                          blank=True)
    campaign_started = models.DateTimeField(_('Campaign Started'), null=True,
                                            blank=True)
    campaign_ended = models.DateTimeField(_('Campaign Ended'), null=True,
                                          blank=True)
    campaign_funded = models.DateTimeField(_('Campaign Funded'), null=True,
                                           blank=True)
    campaign_paid_out = models.DateTimeField(_('Campaign Paid Out'), null=True,
                                             blank=True)
    voting_deadline = models.DateTimeField(_('Voting Deadline'), null=True,
                                           blank=True)

    categories = models.ManyToManyField('categories.Category', blank=True)

    currencies = SelectMultipleField(max_length=100, default=[],
                                     choices=lazy(get_currency_choices, tuple)())

    celebrate_results = models.BooleanField(
        _('Celebrate Results'),
        help_text=_('Show celebration when project is complete'),
        default=True
    )

    PAYOUT_STATUS_CHOICES = (
        (StatusDefinition.NEEDS_APPROVAL, _('Needs approval')),
        (StatusDefinition.APPROVED, _('Approved')),
        (StatusDefinition.SCHEDULED, _('Scheduled')),
        (StatusDefinition.RE_SCHEDULED, _('Re-scheduled')),
        (StatusDefinition.IN_PROGRESS, _('In progress')),
        (StatusDefinition.PARTIAL, _('Partially paid')),
        (StatusDefinition.SUCCESS, _('Success')),
        (StatusDefinition.FAILED, _('Failed'))
    )

    payout_status = models.CharField(max_length=50, null=True, blank=True,
                                     choices=PAYOUT_STATUS_CHOICES)

    def __unicode__(self):
        if self.title:
            return u'{}'.format(self.title)
        return self.slug

    @classmethod
    def update_popularity(self):
        """
        Update popularity score for all projects

        Popularity is calculated by the number of new donations, task members and votes
        in the last 30 days.<commit_msg>Fix project manager for analytics<commit_after>import datetime
import logging

import pytz
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.db.models.aggregates import Count, Sum
from django.db.models.signals import post_init, post_save, pre_save
from django.dispatch import receiver
from django.template.defaultfilters import slugify
from django.utils import timezone
from django.utils.functional import lazy
from django.utils.http import urlquote
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django_extensions.db.fields import ModificationDateTimeField, CreationDateTimeField
from moneyed.classes import Money
from select_multiple_field.models import SelectMultipleField

from bluebottle.analytics.tasks import queue_analytics_record
from bluebottle.bb_metrics.utils import bb_track
from bluebottle.bb_projects.models import (
    BaseProject, ProjectPhase, BaseProjectDocument
)
from bluebottle.clients import properties
from bluebottle.clients.utils import LocalTenant
from bluebottle.tasks.models import Task, TaskMember
from bluebottle.utils.exchange_rates import convert
from bluebottle.utils.fields import MoneyField, get_currency_choices, get_default_currency
from bluebottle.utils.managers import UpdateSignalsQuerySet
from bluebottle.utils.utils import StatusDefinition, PreviousStatusMixin
from bluebottle.wallposts.models import (
    MediaWallpostPhoto, MediaWallpost, TextWallpost
)
from .mails import (
    mail_project_funded_internal, mail_project_complete,
    mail_project_incomplete
)
from .signals import project_funded


logger = logging.getLogger(__name__)


class ProjectPhaseLog(models.Model):
    project = models.ForeignKey('projects.Project')
    status = models.ForeignKey('bb_projects.ProjectPhase')
    start = CreationDateTimeField(
        _('created'), help_text=_('When this project entered in this status.')
    )

    class Analytics:
        type = 'project'
        tags = {
            'id': 'project.id',
            'sub_type': 'project.project_type',
            'status': 'status.name',
            'status_slug': 'status.slug',
            'theme': {
                'project.theme.name': {'translate': True}
            },
            'theme_slug': 'project.theme.slug',
            'location': 'project.location.name',
            'location_group': 'project.location.group.name',
            'country': 'project.country_name'
        }
        fields = {
            'id': 'project.id',
            'user_id': 'project.owner.id'
        }

        @staticmethod
        def timestamp(obj, created):
            return obj.start


class ProjectDocument(BaseProjectDocument):
    @property
    def document_url(self):
        # pk may be unset if not saved yet, in which case no url can be
        # generated.
        if self.pk is not None:
            return reverse('project-document-file', kwargs={'pk': self.pk})
        return None

    @property
    def owner(self):
        return self.project.owner

    @property
    def parent(self):
        return self.project


class Project(BaseProject, PreviousStatusMixin):
    latitude = models.DecimalField(
        _('latitude'), max_digits=21, decimal_places=18, null=True, blank=True)
    longitude = models.DecimalField(
        _('longitude'), max_digits=21, decimal_places=18, null=True, blank=True)

    reach = models.PositiveIntegerField(
        _('Reach'), help_text=_('How many people do you expect to reach?'),
        blank=True, null=True)

    video_url = models.URLField(
        _('video'), max_length=100, blank=True, null=True, default='',
        help_text=_("Do you have a video pitch or a short movie that "
                    "explains your project? Cool! We can't wait to see it! "
                    "You can paste the link to YouTube or Vimeo video here"))

    popularity = models.FloatField(null=False, default=0)
    is_campaign = models.BooleanField(verbose_name='On homepage', default=False, help_text=_(
        "Project is part of a campaign and gets special promotion."))

    skip_monthly = models.BooleanField(_("Skip monthly"),
                                       help_text=_(
                                           "Skip this project when running monthly donations"),
                                       default=False)

    allow_overfunding = models.BooleanField(default=True)
    story = models.TextField(
        _("story"), help_text=_("This is the help text for the story field"),
        blank=True, null=True)

    # TODO: Remove these fields?
    effects = models.TextField(
        _("effects"), blank=True, null=True,
        help_text=_("What will be the Impact? How will your "
                    "Smart Idea change the lives of people?"))
    for_who = models.TextField(
        _("for who"), blank=True, null=True,
        help_text=_("Describe your target group"))
    future = models.TextField(
        _("future"), blank=True, null=True,
        help_text=_("How will this project be self-sufficient and "
                    "sustainable in the long term?"))

    date_submitted = models.DateTimeField(_('Campaign Submitted'), null=True,
                                          blank=True)
    campaign_started = models.DateTimeField(_('Campaign Started'), null=True,
                                            blank=True)
    campaign_ended = models.DateTimeField(_('Campaign Ended'), null=True,
                                          blank=True)
    campaign_funded = models.DateTimeField(_('Campaign Funded'), null=True,
                                           blank=True)
    campaign_paid_out = models.DateTimeField(_('Campaign Paid Out'), null=True,
                                             blank=True)
    voting_deadline = models.DateTimeField(_('Voting Deadline'), null=True,
                                           blank=True)

    categories = models.ManyToManyField('categories.Category', blank=True)

    currencies = SelectMultipleField(max_length=100, default=[],
                                     choices=lazy(get_currency_choices, tuple)())

    celebrate_results = models.BooleanField(
        _('Celebrate Results'),
        help_text=_('Show celebration when project is complete'),
        default=True
    )

    PAYOUT_STATUS_CHOICES = (
        (StatusDefinition.NEEDS_APPROVAL, _('Needs approval')),
        (StatusDefinition.APPROVED, _('Approved')),
        (StatusDefinition.SCHEDULED, _('Scheduled')),
        (StatusDefinition.RE_SCHEDULED, _('Re-scheduled')),
        (StatusDefinition.IN_PROGRESS, _('In progress')),
        (StatusDefinition.PARTIAL, _('Partially paid')),
        (StatusDefinition.SUCCESS, _('Success')),
        (StatusDefinition.FAILED, _('Failed'))
    )

    payout_status = models.CharField(max_length=50, null=True, blank=True,
                                     choices=PAYOUT_STATUS_CHOICES)

    objects = UpdateSignalsQuerySet.as_manager()

    def __unicode__(self):
        if self.title:
            return u'{}'.format(self.title)
        return self.slug

    @classmethod
    def update_popularity(self):
        """
        Update popularity score for all projects

        Popularity is calculated by the number of new donations, task members and votes
        in the last 30 days.
{'fraction_non_alphanumeric': 0.0936654033567948, 'fraction_numerical': 0.0025717379534380075, 'mean_word_length': 2.696098049024512, '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': 36, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6485257', 'n_tokens_mistral': 3980, 'n_tokens_neox': 3880, 'n_words': 1027}