addons-server/apps/stats/models.py

290 строки
9.0 KiB
Python
Исходник Обычный вид История

import datetime
from django.conf import settings
from django.db import models
from django.template import Context, loader
import caching.base
import tower
from tower import ugettext as _
import amo
from amo.models import ModelBase
from amo.fields import DecimalCharField
2010-11-16 22:31:38 +03:00
from amo.utils import send_mail
from .db import StatsDictField, StatsManager
2010-05-04 11:26:10 +04:00
class AddonCollectionCount(caching.base.CachingMixin, models.Model):
addon = models.ForeignKey('addons.Addon')
collection = models.ForeignKey('bandwagon.Collection')
count = models.PositiveIntegerField()
date = models.DateField()
class Meta:
db_table = 'stats_addons_collections_counts'
class CollectionCount(caching.base.CachingMixin, models.Model):
collection = models.ForeignKey('bandwagon.Collection')
count = models.PositiveIntegerField()
date = models.DateField()
2010-05-13 06:10:52 +04:00
objects = models.Manager()
stats = StatsManager('date')
class Meta:
db_table = 'stats_collections_counts'
2010-05-04 10:44:31 +04:00
class CollectionStats(caching.base.CachingMixin, models.Model):
"""In the running for worst-named model ever."""
collection = models.ForeignKey('bandwagon.Collection')
name = models.CharField(max_length=255, null=True)
count = models.PositiveIntegerField()
date = models.DateField()
class Meta:
db_table = 'stats_collections'
class DownloadCount(caching.base.CachingMixin, models.Model):
addon = models.ForeignKey('addons.Addon')
count = models.PositiveIntegerField()
date = models.DateField()
# Leave this out of queries if you can.
sources = StatsDictField(db_column='src', null=True)
2010-05-13 06:10:52 +04:00
objects = models.Manager()
stats = StatsManager('date')
class Meta:
db_table = 'download_counts'
2010-08-13 20:24:36 +04:00
def flush_urls(self):
return ['*/addon/%d/statistics/downloads*' % self.addon_id, ]
class UpdateCount(caching.base.CachingMixin, models.Model):
addon = models.ForeignKey('addons.Addon')
count = models.PositiveIntegerField()
date = models.DateField()
# Leave these out of queries if you can.
versions = StatsDictField(db_column='version', null=True)
statuses = StatsDictField(db_column='status', null=True)
applications = StatsDictField(db_column='application', null=True)
oses = StatsDictField(db_column='os', null=True)
locales = StatsDictField(db_column='locale', null=True)
2010-05-13 06:10:52 +04:00
objects = models.Manager()
stats = StatsManager('date')
class Meta:
db_table = 'update_counts'
2010-08-13 20:24:36 +04:00
def flush_urls(self):
return ['*/addon/%d/statistics/usage*' % self.addon_id, ]
2010-08-25 02:22:15 +04:00
class AddonShareCount(caching.base.CachingMixin, models.Model):
addon = models.ForeignKey('addons.Addon')
count = models.PositiveIntegerField()
service = models.CharField(max_length=255, null=True)
date = models.DateField()
2010-05-13 06:10:52 +04:00
objects = models.Manager()
stats = StatsManager('date')
class Meta:
db_table = 'stats_share_counts'
2010-08-25 02:22:15 +04:00
class AddonShareCountTotal(caching.base.CachingMixin, models.Model):
2010-04-03 00:49:46 +04:00
addon = models.ForeignKey('addons.Addon')
count = models.PositiveIntegerField()
service = models.CharField(max_length=255, null=True)
2010-05-14 00:32:53 +04:00
objects = caching.base.CachingManager()
2010-05-13 06:10:52 +04:00
stats = caching.base.CachingManager()
2010-04-03 00:49:46 +04:00
class Meta:
db_table = 'stats_share_counts_totals'
2010-08-25 02:22:15 +04:00
# stats_collections_share_counts exists too, but we don't touch it.
class CollectionShareCountTotal(caching.base.CachingMixin, models.Model):
collection = models.ForeignKey('bandwagon.Collection')
count = models.PositiveIntegerField()
service = models.CharField(max_length=255, null=True)
objects = caching.base.CachingManager()
class Meta:
db_table = 'stats_collections_share_counts_totals'
class ContributionError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class Contribution(caching.base.CachingMixin, models.Model):
addon = models.ForeignKey('addons.Addon')
charity = models.ForeignKey('addons.Charity', null=True)
amount = DecimalCharField(max_digits=9, decimal_places=2,
nullify_invalid=True, null=True)
source = models.CharField(max_length=255, null=True)
source_locale = models.CharField(max_length=10, null=True)
annoying = models.PositiveIntegerField(
choices=amo.CONTRIB_CHOICES, default=0)
created = models.DateTimeField(auto_now_add=True)
uuid = models.CharField(max_length=255, null=True)
is_suggested = models.BooleanField()
suggested_amount = DecimalCharField(max_digits=254, decimal_places=2,
nullify_invalid=True, null=True)
comment = models.CharField(max_length=255)
transaction_id = models.CharField(max_length=255, null=True)
post_data = StatsDictField(null=True)
2010-05-13 06:10:52 +04:00
objects = models.Manager()
stats = StatsManager('created')
class Meta:
db_table = 'stats_contributions'
def __unicode__(self):
return u'%s: %s' % (self.addon.name, self.amount)
2010-08-13 20:24:36 +04:00
def flush_urls(self):
return ['*/addon/%d/statistics/contributions*' % self.addon_id, ]
@property
def date(self):
try:
return datetime.date(self.created.year,
self.created.month, self.created.day)
except AttributeError:
# created may be None
return None
@property
def contributor(self):
try:
return u'%s %s' % (self.post_data['first_name'],
self.post_data['last_name'])
except (TypeError, KeyError):
# post_data may be None or missing a key
return None
@property
def email(self):
try:
return self.post_data['payer_email']
except (TypeError, KeyError):
# post_data may be None or missing a key
return None
2010-02-27 04:43:30 +03:00
def mail_thankyou(self, request=None):
"""
Mail a thankyou note for a completed contribution.
Raises a ``ContributionError`` exception when the contribution
is not complete or email addresses are not found.
"""
# Setup l10n before loading addon.
if self.source_locale:
lang = self.source_locale
else:
lang = self.addon.default_locale
tower.activate(lang)
# Thankyous must be enabled.
if not self.addon.enable_thankyou:
# Not an error condition, just return.
return
# Contribution must be complete.
if not self.transaction_id:
raise ContributionError('Transaction not complete')
# Send from support_email, developer's email, or default.
2010-04-10 07:49:36 +04:00
from_email = settings.DEFAULT_FROM_EMAIL
if self.addon.support_email:
from_email = str(self.addon.support_email)
else:
try:
author = self.addon.listed_authors[0]
if author.email and not author.emailhidden:
from_email = author.email
except (IndexError, TypeError):
# This shouldn't happen, but the default set above is still ok.
pass
# We need the contributor's email.
to_email = self.post_data['payer_email']
if not to_email:
raise ContributionError('Empty payer email')
# Make sure the url uses the right language.
# Setting a prefixer would be nicer, but that requires a request.
2010-03-19 22:44:24 +03:00
url_parts = self.addon.meet_the_dev_url().split('/')
url_parts[1] = lang
# Buildup the email components.
t = loader.get_template('stats/contribution-thankyou-email.ltxt')
c = {
'thankyou_note': self.addon.thankyou_note,
'addon_name': self.addon.name,
'learn_url': '%s%s?src=emailinfo' % (settings.SITE_URL,
'/'.join(url_parts)),
2010-03-18 00:23:48 +03:00
'domain': settings.DOMAIN,
}
body = t.render(Context(c))
subject = _('Thanks for contributing to {addon_name}').format(
addon_name=self.addon.name)
# Send the email
2010-11-16 22:31:38 +03:00
if send_mail(subject, body, from_email, [to_email],
fail_silently=True):
# Clear out contributor identifying information.
del(self.post_data['payer_email'])
self.save()
@staticmethod
def post_save(sender, instance, **kwargs):
from . import tasks
2010-06-30 06:09:35 +04:00
tasks.addon_total_contributions.delay(instance.addon_id)
models.signals.post_save.connect(Contribution.post_save, sender=Contribution)
2010-02-27 04:43:30 +03:00
class SubscriptionEvent(ModelBase):
"""Save subscription info for future processing."""
post_data = StatsDictField()
class Meta:
db_table = 'subscription_events'
2010-02-27 04:43:30 +03:00
class GlobalStat(caching.base.CachingMixin, models.Model):
name = models.CharField(max_length=255)
count = models.IntegerField()
date = models.DateField()
2010-05-14 00:32:53 +04:00
objects = caching.base.CachingManager()
2010-05-13 06:10:52 +04:00
stats = caching.base.CachingManager()
2010-02-27 04:43:30 +03:00
class Meta:
db_table = 'global_stats'
unique_together = ('name', 'date')
get_latest_by = 'date'