Skip to content

Instantly share code, notes, and snippets.

@graingert
Created August 19, 2011 16:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save graingert/1157299 to your computer and use it in GitHub Desktop.
Save graingert/1157299 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
"horfunk.radiopirate models and events handlers"
import datetime
import os
import logging
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from product.modules.subscription.models import SubscriptionProduct \
as SatchmoSubscriptionProduct
from satchmo_store.shop import signals as satchmo_signals
from horfunk.shows.models.podcasts import Podcast
from horfunk.streams.models import StreamContentGroup
import horfunk.radiopirate.cache
from horfunk.utils import user_profile
from sg.django_tools.cache import CachedInvalidator
logger = logging.getLogger(__name__)
class PodcastSubscription(models.Model):
"Subscribed user to a podcast"
user = models.ForeignKey(
User,
verbose_name=_("user"),
help_text=_("Subscribed user"))
podcast = models.ForeignKey(
Podcast,
verbose_name=_("podcast"),
help_text=_("Subscribed podcast"))
# regular subscription
expiration = models.DateField(
_("Expiration"),
help_text=_("Date when user subscription expire"))
# podcast on demand
tokens_expiration = models.DateField(
_("Tokens expiration"),
null=True, blank=True,
help_text=_("Date when tokens expires"))
tokens = models.PositiveIntegerField(
_("Remaining tokens"),
default=0,
help_text=_("Number of tokens user can spend on podcast download"))
@property
def is_expired(self):
"return True if subscription is expired"
return self.expiration <= datetime.datetime.now().date()
def __unicode__(self):
"return string representation of this PodcastSubscription instance"
return '%s for %s' % (self.user, self.podcast.slug)
class Meta:
"Metadata of PodcastSubscription"
verbose_name = _('podcast subscription')
verbose_name_plural = _('podcast subscriptions')
ordering = ('expiration', 'podcast', 'user',)
unique_together = ('user', 'podcast',)
class StreamSubscription(models.Model):
"Subscribed user to a stream content group"
user = models.ForeignKey(
User,
verbose_name=_("user"),
help_text=_("Subscribed user"))
stream = models.ForeignKey(
StreamContentGroup,
verbose_name=_("stream content group"),
help_text=_("Subscribed stream content group"))
# regular subscription
expiration = models.DateField(
_("Expiration"),
help_text=_("Date when user subscription expire"))
@property
def is_expired(self):
"return True if subscription is expired"
return self.expiration <= datetime.datetime.now().date()
def __unicode__(self):
"return string representation of this StreamSubscription instance"
return '%s | %s' % (self.user, self.stream)
class Meta:
"Metadata of StreamSubscription"
verbose_name = _('stream content group subscription')
verbose_name_plural = _('stream content group subscriptions')
ordering = ('expiration', 'stream', 'user',)
unique_together = ('user', 'stream',)
def extend_subscription(subscription, expire_date, log_prefix):
"""Pick an existing subscription and update or extend expiration date
:type: subscription: :class:`PodcastSubscription` or
:class:`StreamContentGroupSubscription`
:param: subscription: subscription instance to check
:type: expire_date: :class:`datetime.date`
:param: expire_date: new expiration date
:type: log_prefix: string
:param: log_prefix: message that will be in front of each log message
"""
today = datetime.datetime.now().date()
if subscription.expiration < today:
logger.debug("%s renew subscription that expired %s", log_prefix,
subscription.expiration)
subscription.expiration = expire_date
subscription.save()
else:
remaining = subscription.expiration - today
logger.info("%s renew subscription that was expiring in %d days",
log_prefix, remaining.days)
subscription.expiration = expire_date + remaining
logger.info("%s Order expires date %s is shifted to %s", log_prefix,
expire_date, subscription.expiration)
subscription.save()
class SubscriptionProduct(models.Model):
"Satchmo Product Subscription"
product = models.ForeignKey(
SatchmoSubscriptionProduct,
unique=True,
verbose_name=_("Associated Store Product"),
help_text=_("Select the Subscription Product in Store "
"associated to this entry"))
podcasts = models.ManyToManyField(
Podcast,
null=True,
blank=True,
help_text=_("List of one or more podcast the customer will"
"be subscribed to"),
verbose_name=_("subscribing podcast"))
streams = models.ManyToManyField(
StreamContentGroup,
null=True,
blank=True,
help_text=_("List of one or more audio stream content the customer will"
"be subscribed to"),
verbose_name=_("subscribing audio stream"))
description = models.TextField(
_("description"),
blank=True,
help_text=_("Optional description of this Subscription Product"),
max_length=2048)
def __unicode__(self):
"return real product slug"
return self.product.product.slug
def new_order(self, expire_date, user):
"""New order for this subscription product
type: expire_date: :class:`datetime.date`
param: expire_date: date when the subscription is suposed to expires
type: user: :class:`django.contrib.auth.models.User`
param: user: user who complete the order
"""
# a profile is required past this point
if not user_profile(user):
logger.info("user %s did not have a profile yet, create one with"
"default values", user)
new_profile = Profile(user=user)
new_profile.save()
# start with podcast
for podcast in self.podcasts.all():
log_prefix = "new_order Podcast[%s] User[%s]:" % (podcast, user)
try:
existing = PodcastSubscription.objects.get(user=user,
podcast=podcast)
extend_subscription(existing, expire_date, log_prefix)
except PodcastSubscription.DoesNotExist:
logger.debug("%s is a new subscription", log_prefix)
new_subscription = PodcastSubscription(user=user,
podcast=podcast,
expiration=expire_date)
new_subscription.save()
# then stream content group
for content_group in self.streams.all():
log_prefix = "StreamContentGroup[%s] User[%s]:" % (content_group,
user)
try:
existing = StreamSubscription.objects.get(user=user,
stream=content_group)
extend_subscription(existing, expire_date, log_prefix)
except StreamSubscription.DoesNotExist:
logger.debug("%s is a new subscription", log_prefix)
new_subscription = StreamSubscription(user=user,
stream=content_group,
expiration=expire_date)
new_subscription.save()
class Meta:
"Metadata of RPSubscriptionProduct"
verbose_name = _('RadioPirate.com Subscription product')
verbose_name_plural = _('RadioPirate.com Subscription products')
class Profile(models.Model):
"""
Profile of a single User in RadioPirate.com website
"""
user = models.OneToOneField(
User,
unique=True)
public_profile_field = models.BooleanField(
_("Is public"),
help_text=_("Is your profile public to other members"),
default=False)
suggesting_user = models.ForeignKey(User,
null=True,
related_name = "suggestions")
# subscriptions
@property
def podcast_subscriptions(self):
"return QuerySet of podcast subscription of this user profile"
subscriptions = PodcastSubscription.objects.filter(user=self.user)
logger.debug("User[%s] got %d podcast subscriptions",
self.user, len(subscriptions))
return subscriptions
@property
def stream_subscriptions(self):
"return QuerySet of subscription of this user profile"
subscriptions = StreamSubscription.objects.filter(user=self.user)
logger.debug("User[%s] got %d stream subscriptions",
self.user, len(subscriptions))
return subscriptions
@models.permalink
def get_absolute_url(self):
"return this profile instance URL"
return 'profiles_profile_detail', [self.user.username]
class Meta:
"Profile metadata"
verbose_name = _('profile')
verbose_name_plural = _('profiles')
ordering = ('user',)
class RadioGroup(models.Model):
"Group of radio station"
title = models.CharField(
_("name of this group of radio"),
max_length=140,
unique=True,
help_text=_("One-liner naming the group of radio"))
description = models.TextField(
_("radio group description"),
blank=True,
help_text=_("Radio group description in HTML"),
max_length=2048)
slug = models.SlugField(
_("URL compatible name"),
unique=True,
help_text=_("URL compatible name, used for template directory too"))
content_group = models.ManyToManyField(
StreamContentGroup,
verbose_name=_("List of stream content group"),
help_text=_("List of StreamContentGroup in this group of radio"))
def __unicode__(self):
return '%s (%s)' % (self.title, self.slug)
@models.permalink
def get_absolute_url(self):
"return absolute URL of this instance"
return 'radiogroup_index', [self.slug]
def template_file(self, prefix, extension='html', root='radios'):
"""
return template file for specified prefix filename
the template file name is create from:
%(root)s/%(radiogroup.slug)%/%(prefix).%(extension)
so, for radiogroup with slug 'rock' will be, by default:
"radios/rock/%(prefix).html"
"""
# append .html
filename = os.extsep.join((prefix, extension))
return os.sep.join((root, self.slug, filename))
class Meta:
"Metadata for RadioGroup"
verbose_name = _("group of radio station")
verbose_name_plural = _("groups of radio station")
ordering = ('slug',)
class ContactCategory(models.Model):
"""
Contact category recipients
"""
name = models.CharField(
_('name'),
max_length=256,
unique=True,
help_text=_('User displayed text associatedto this category'))
recipient = models.EmailField(
_('recipient email'),
help_text=_('mail is sent to this address when a'
'new contact message is submited'))
def __unicode__(self):
return self.name
class Meta:
"ContactCategory metadata"
verbose_name = _('contact category')
verbose_name_plural = _('contact categories')
ordering = ('name', 'recipient')
class AffiliationRequest(models.Model):
submitter = models.ForeignKey(User)
referrals =
def AffilateJunction(models.Model):
request = models.ForeignKey(AffiliationRequest)
referral = models.ForeignKey(User)
approved = BooleanField(default=False)
def _meta():
unique_together = ("request", "referral")
def subscription_sale_listener(order=None, **kwargs):
"""
Signal receiver function that listen to all complted Satchmo
orders and look if a purchased product is a RadioPirate subscription
"""
logger.debug("New sale!")
if order:
log_prefix = "order #%i: " % order.id
for item in order.orderitem_set.all():
item_log = log_prefix + "product '%s': " % item.product.slug
if item.product.is_subscription:
logger.debug("%sis a subscription", item_log)
try:
subscription_product = SubscriptionProduct.objects.get(
product=item.product)
logger.debug("%sis a RP Subscription", item_log)
subscription_product.new_order(item.expire_date,
order.contact.user)
except SubscriptionProduct.DoesNotExist:
logger.debug("%sis not RP subscription", item_log)
else:
logger.debug("%snot a subscription, ignore it", item_log)
else:
logger.error("No order?")
INVALIDATOR = CachedInvalidator({
StreamSubscription: ('subscriptions', 'subscriptions-episodes'),
PodcastSubscription: ('subscriptions', 'subscriptions-episodes')})
horfunk.radiopirate.cache.connect(
{Profile: horfunk.radiopirate.cache.invalidate_profile})
satchmo_signals.order_success.connect(subscription_sale_listener)
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment