342 lines
18 KiB
Python
342 lines
18 KiB
Python
"""
|
|
external library imports
|
|
"""
|
|
import datetime
|
|
import itertools
|
|
import logging
|
|
|
|
from tastypie.models import create_api_key
|
|
|
|
"""
|
|
django imports
|
|
"""
|
|
import django.dispatch
|
|
|
|
from django.conf import settings
|
|
from django.contrib.auth.models import User
|
|
from django.contrib.sites.models import Site
|
|
from django.db.models import get_model, signals
|
|
from django.db.models.signals import post_save
|
|
from django.db.utils import DatabaseError
|
|
from django.dispatch import Signal
|
|
from django.utils.translation import ugettext_noop as _
|
|
from django.template.loader import render_to_string
|
|
|
|
from notification import models as notification
|
|
|
|
"""
|
|
regluit imports
|
|
"""
|
|
from regluit.payment.signals import transaction_charged, transaction_failed, pledge_modified, pledge_created
|
|
from regluit.utils.localdatetime import now, date_today
|
|
from regluit.core.parameters import REWARDS, BUY2UNGLUE, THANKS, LIBRARY, RESERVE, THANKED
|
|
from regluit.libraryauth.models import Library, LibraryUser
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# create Wishlist and UserProfile to associate with User
|
|
def create_user_objects(sender, created, instance, **kwargs):
|
|
# use get_model to avoid circular import problem with models
|
|
# don't create Wishlist or UserProfile if we are loading fixtures http://stackoverflow.com/a/3500009/7782
|
|
if not kwargs.get('raw', False):
|
|
try:
|
|
Wishlist = get_model('core', 'Wishlist')
|
|
UserProfile = get_model('core', 'UserProfile')
|
|
if created:
|
|
Wishlist.objects.create(user=instance)
|
|
profile = UserProfile.objects.create(user=instance)
|
|
profile.ml_subscribe()
|
|
except DatabaseError:
|
|
# this can happen when creating superuser during syncdb since the
|
|
# core_wishlist table doesn't exist yet
|
|
return
|
|
|
|
post_save.connect(create_user_objects, sender=User)
|
|
|
|
|
|
# create API key for new User
|
|
post_save.connect(create_api_key, sender=User)
|
|
|
|
|
|
# create notification types (using django-notification) -- tie to syncdb
|
|
|
|
def create_notice_types(app, created_models, verbosity, **kwargs):
|
|
notification.create_notice_type("comment_on_commented", _("Comment on Commented Work"), _("A comment has been received on a book that you've commented on."))
|
|
notification.create_notice_type("wishlist_comment", _("Book List Comment"), _("A comment has been received on one of your books."), default = 1)
|
|
notification.create_notice_type("wishlist_official_comment", _("Book List Comment"), _("The author or publisher, or and Unglue.it staffer, has commented on one of your faves."))
|
|
notification.create_notice_type("wishlist_work_claimed", _("Rights Holder is Active"), _("A rights holder has shown up for a book that you've faved."), default = 1)
|
|
notification.create_notice_type("wishlist_active", _("New Campaign"), _("A book you've favorited has a newly launched campaign."))
|
|
notification.create_notice_type("wishlist_near_target", _("Campaign Near Target"), _("A book you want is near its ungluing target."))
|
|
notification.create_notice_type("wishlist_near_deadline", _("Campaign Near Deadline"), _("A book you want is almost out of time."))
|
|
notification.create_notice_type("wishlist_premium_limited_supply", _("Only a Few Premiums Left"), _("A limited edition premium is running out on a book you've faved."))
|
|
notification.create_notice_type("wishlist_successful", _("Successful Campaign"), _("An ungluing campaign that you have supported or faved has succeeded."))
|
|
notification.create_notice_type("wishlist_unsuccessful", _("Unsuccessful Campaign"), _("An ungluing campaign that you supported didn't succeed this time."))
|
|
notification.create_notice_type("wishlist_updated", _("Campaign Updated"), _("An ungluing campaign you support has been updated."), default = 1)
|
|
notification.create_notice_type("wishlist_message", _("Campaign Communication"), _("You have a private message from unglue.it staff or the rights holder about a book you've faved."))
|
|
notification.create_notice_type("wishlist_price_drop", _("Campaign Price Drop"), _("An ungluing campaign you've faved has a reduced target."), default = 1)
|
|
notification.create_notice_type("wishlist_unglued_book_released", _("Unglued Book!"), _("A book you've faved is now available to be downloaded."))
|
|
notification.create_notice_type("pledge_you_have_pledged", _("Thanks For Your Pledge!"), _("Your ungluing pledge has been entered."))
|
|
notification.create_notice_type("pledge_status_change", _("Your Pledge Has Been Modified"), _("Your ungluing pledge has been modified."))
|
|
notification.create_notice_type("pledge_charged", _("Your Pledge has been Executed"), _("You have contributed to a successful ungluing campaign."))
|
|
notification.create_notice_type("pledge_failed", _("Unable to charge your credit card"), _("A charge to your credit card did not go through."))
|
|
notification.create_notice_type("rights_holder_created", _("Agreement Accepted"), _("You have become a verified Unglue.it rights holder."))
|
|
notification.create_notice_type("rights_holder_claim", _("Claim Entered"), _("A claim has been entered."))
|
|
notification.create_notice_type("wishlist_unsuccessful_amazon", _("Campaign shut down"), _("An ungluing campaign that you supported had to be shut down due to an Amazon Payments policy change."))
|
|
notification.create_notice_type("pledge_gift_credit", _("Gift Credit Balance"), _("You have a gift credit balance"))
|
|
notification.create_notice_type("new_wisher", _("New wisher"), _("Someone new has faved a book that you're the rightsholder for"))
|
|
notification.create_notice_type("account_expiring", _("Credit Card Expiring Soon"), _("Your credit card is about to expire."))
|
|
notification.create_notice_type("account_expired", _("Credit Card Has Expired"), _("Your credit card has expired."))
|
|
notification.create_notice_type("account_active", _("Credit Card Number Updated"), _("Payment method updated."), default = 1)
|
|
notification.create_notice_type("purchase_complete", _("Your Purchase is Complete"), _("Your Unglue.it Purchase is Complete."))
|
|
notification.create_notice_type("library_borrow", _("Library eBook Borrowed."), _("You've borrowed an ebook through a Library participating in Unglue.it"))
|
|
notification.create_notice_type("library_reserve", _("Library eBook Reserved."), _("An ebook you've reserved is available."))
|
|
notification.create_notice_type("library_join", _("New Library User."), _("A library participating in Unglue.it has added a user"))
|
|
notification.create_notice_type("purchase_gift", _("You have a gift."), _("An ungluer has given you an ebook."))
|
|
notification.create_notice_type("purchase_got_gift", _("Your gift was received."), _("The ebook you sent as a gift has been redeemed."))
|
|
notification.create_notice_type("purchase_gift_waiting", _("Your gift is waiting."), _("Please claim your ebook."))
|
|
notification.create_notice_type("purchase_notgot_gift", _("Your gift wasn't received."), _("The ebook you sent as a gift has not yet been redeemed."))
|
|
|
|
signals.post_syncdb.connect(create_notice_types, sender=notification)
|
|
|
|
# define the notifications and tie them to corresponding signals
|
|
|
|
from django.contrib.comments.signals import comment_was_posted
|
|
|
|
def notify_comment(comment, request, **kwargs):
|
|
logger.info('comment %s notifying' % comment.pk)
|
|
other_commenters = User.objects.filter(comment_comments__content_type=comment.content_type, comment_comments__object_pk=comment.object_pk).distinct().exclude(id=comment.user.id)
|
|
all_wishers = comment.content_object.wished_by().exclude(id=comment.user.id)
|
|
other_wishers = all_wishers.exclude(id__in=other_commenters)
|
|
domain = Site.objects.get_current().domain
|
|
if comment.content_object.last_campaign() and comment.user in comment.content_object.last_campaign().managers.all():
|
|
#official
|
|
notification.queue(all_wishers, "wishlist_official_comment", {'comment':comment, 'domain':domain}, True)
|
|
else:
|
|
notification.send(other_commenters, "comment_on_commented", {'comment':comment}, True, sender=comment.user)
|
|
notification.send(other_wishers, "wishlist_comment", {'comment':comment}, True, sender=comment.user)
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
comment_was_posted.connect(notify_comment)
|
|
|
|
# Successful campaign signal
|
|
# https://code.djangoproject.com/browser/django/tags/releases/1.3.1/django/db/models/signals.py
|
|
|
|
successful_campaign = Signal(providing_args=["campaign"])
|
|
|
|
def notify_successful_campaign(campaign, **kwargs):
|
|
"""send notification in response to successful campaign"""
|
|
logger.info('received successful_campaign signal for {0}'.format(campaign))
|
|
# supporters and staff -- though it might be annoying for staff to be getting all these notices!
|
|
staff = User.objects.filter(is_staff=True)
|
|
supporters = (User.objects.get(id=k) for k in campaign.supporters())
|
|
|
|
notification.send(itertools.chain(staff, supporters), "wishlist_successful", {'campaign':campaign}, True)
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
# successful_campaign -> send notices
|
|
successful_campaign.connect(notify_successful_campaign)
|
|
|
|
unsuccessful_campaign = Signal(providing_args=["campaign"])
|
|
|
|
def notify_unsuccessful_campaign(campaign, **kwargs):
|
|
"""send notification in response to unsuccessful campaign"""
|
|
logger.info('received unsuccessful_campaign signal for {0}'.format(campaign))
|
|
# supporters and staff -- though it might be annoying for staff to be getting all these notices!
|
|
staff = User.objects.filter(is_staff=True)
|
|
supporters = (User.objects.get(id=k) for k in campaign.supporters())
|
|
|
|
notification.send(itertools.chain(staff, supporters), "wishlist_unsuccessful", {'campaign':campaign}, True)
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
# unsuccessful_campaign -> send notices
|
|
unsuccessful_campaign.connect(notify_unsuccessful_campaign)
|
|
|
|
def handle_transaction_charged(sender,transaction=None, **kwargs):
|
|
if transaction==None:
|
|
return
|
|
transaction._current_total = None
|
|
context = {'transaction':transaction,'current_site':Site.objects.get_current()}
|
|
if transaction.campaign.type is REWARDS:
|
|
notification.send([transaction.user], "pledge_charged", context, True)
|
|
elif transaction.campaign.type is BUY2UNGLUE:
|
|
# provision the book
|
|
Acq = get_model('core', 'Acq')
|
|
if transaction.offer.license == LIBRARY:
|
|
library = Library.objects.get(id=transaction.extra['library_id'])
|
|
new_acq = Acq.objects.create(user=library.user,work=transaction.campaign.work,license= LIBRARY)
|
|
if transaction.user.id != library.user.id: # don't put it on reserve if purchased by the library
|
|
reserve_acq = Acq.objects.create(user=transaction.user,work=transaction.campaign.work,license= RESERVE, lib_acq = new_acq)
|
|
reserve_acq.expire_in(datetime.timedelta(hours=2))
|
|
copies = int(transaction.extra.get('copies',1))
|
|
while copies > 1:
|
|
Acq.objects.create(user=library.user,work=transaction.campaign.work,license= LIBRARY)
|
|
copies -= 1
|
|
else:
|
|
if transaction.extra.get('give_to', False):
|
|
# it's a gift!
|
|
Gift = get_model('core', 'Gift')
|
|
giftee = Gift.giftee(transaction.extra['give_to'], str(transaction.id))
|
|
new_acq = Acq.objects.create(user=giftee, work=transaction.campaign.work, license= transaction.offer.license)
|
|
gift = Gift.objects.create(acq=new_acq, message=transaction.extra.get('give_message',''), giver=transaction.user , to = transaction.extra['give_to'])
|
|
context['gift'] = gift
|
|
notification.send([giftee], "purchase_gift", context, True)
|
|
else:
|
|
new_acq = Acq.objects.create(user=transaction.user,work=transaction.campaign.work,license= transaction.offer.license)
|
|
transaction.campaign.update_left()
|
|
notification.send([transaction.user], "purchase_complete", context, True)
|
|
from regluit.core.tasks import watermark_acq
|
|
watermark_acq.delay(new_acq)
|
|
if transaction.campaign.cc_date < date_today() :
|
|
transaction.campaign.update_status(send_notice=True)
|
|
elif transaction.campaign.type is THANKS:
|
|
if transaction.user:
|
|
Acq = get_model('core', 'Acq')
|
|
new_acq = Acq.objects.create(user=transaction.user, work=transaction.campaign.work, license=THANKED)
|
|
notification.send([transaction.user], "purchase_complete", context, True)
|
|
elif transaction.receipt:
|
|
from regluit.core.tasks import send_mail_task
|
|
message = render_to_string("notification/purchase_complete/full.txt", context )
|
|
send_mail_task.delay('unglue.it transaction confirmation', message, 'notices@gluejar.com', [transaction.receipt])
|
|
if transaction.user:
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
transaction_charged.connect(handle_transaction_charged)
|
|
|
|
# dealing with failed transactions
|
|
|
|
def handle_transaction_failed(sender,transaction=None, **kwargs):
|
|
if transaction is None or transaction.campaign.type == THANKS:
|
|
# no need to nag a failed THANKS transaction
|
|
return
|
|
|
|
# window for recharging
|
|
recharge_deadline = transaction.campaign.deadline_or_now + datetime.timedelta(settings.RECHARGE_WINDOW)
|
|
|
|
notification.send([transaction.user], "pledge_failed", {
|
|
'transaction':transaction,
|
|
'recharge_deadline': recharge_deadline
|
|
}, True)
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
transaction_failed.connect(handle_transaction_failed)
|
|
|
|
|
|
def handle_pledge_modified(sender, transaction=None, up_or_down=None, **kwargs):
|
|
# we need to know if pledges were modified up or down because Amazon handles the
|
|
# transactions in different ways, resulting in different user-visible behavior;
|
|
# we need to set expectations appropriately
|
|
# up_or_down is 'increased', 'decreased', or 'canceled'
|
|
if transaction==None or up_or_down==None:
|
|
return
|
|
if up_or_down == 'canceled':
|
|
transaction.user.profile.reset_pledge_badge()
|
|
notification.send([transaction.user], "pledge_status_change", {
|
|
'transaction': transaction,
|
|
'up_or_down': up_or_down
|
|
}, True)
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
pledge_modified.connect(handle_pledge_modified)
|
|
|
|
def handle_you_have_pledged(sender, transaction=None, **kwargs):
|
|
if transaction==None:
|
|
return
|
|
|
|
#give user a badge
|
|
if not transaction.anonymous:
|
|
transaction.user.profile.reset_pledge_badge()
|
|
|
|
notification.send([transaction.user], "pledge_you_have_pledged", {
|
|
'transaction': transaction
|
|
}, True)
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
pledge_created.connect(handle_you_have_pledged)
|
|
|
|
amazon_suspension = Signal(providing_args=["campaign"])
|
|
|
|
def handle_wishlist_unsuccessful_amazon(campaign, **kwargs):
|
|
"""send notification in response to campaign shutdown following Amazon suspension"""
|
|
logger.info('received amazon_suspension signal for {0}'.format(campaign))
|
|
# supporters and staff -- though it might be annoying for staff to be getting all these notices!
|
|
staff = User.objects.filter(is_staff=True)
|
|
supporters = (User.objects.get(id=k) for k in campaign.supporters())
|
|
|
|
notification.send(itertools.chain(staff, supporters), "wishlist_unsuccessful_amazon", {'campaign':campaign}, True)
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
amazon_suspension.connect(handle_wishlist_unsuccessful_amazon)
|
|
|
|
wishlist_added = Signal(providing_args=["supporter", "work"])
|
|
|
|
def handle_wishlist_added(supporter, work, **kwargs):
|
|
"""send notification to confirmed rights holder when someone wishes for their work"""
|
|
claim = work.claim.filter(status="active")
|
|
if claim:
|
|
notification.send([claim[0].user], "new_wisher", {
|
|
'supporter': supporter,
|
|
'work': work,
|
|
'base_url': settings.BASE_URL_SECURE,
|
|
}, True)
|
|
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
wishlist_added.connect(handle_wishlist_added)
|
|
|
|
deadline_impending = Signal(providing_args=["campaign"])
|
|
|
|
def handle_wishlist_near_deadline(campaign, **kwargs):
|
|
"""
|
|
send two groups - one the nonpledgers, one the pledgers
|
|
set the pledged flag differently in the context
|
|
"""
|
|
pledgers = campaign.ungluers()['all']
|
|
nonpledgers = campaign.work.wished_by().exclude(id__in=[p.id for p in pledgers])
|
|
|
|
notification.send(pledgers, "wishlist_near_deadline", {
|
|
'campaign': campaign,
|
|
'domain': settings.BASE_URL_SECURE,
|
|
'pledged': True,
|
|
}, True)
|
|
|
|
notification.send(nonpledgers, "wishlist_near_deadline", {
|
|
'campaign': campaign,
|
|
'domain': settings.BASE_URL_SECURE,
|
|
'pledged': False,
|
|
}, True)
|
|
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
deadline_impending.connect(handle_wishlist_near_deadline)
|
|
|
|
supporter_message = Signal(providing_args=["supporter", "work", "msg"])
|
|
|
|
def notify_supporter_message(sender, work, supporter, msg, **kwargs):
|
|
"""send notification in of supporter message"""
|
|
logger.info('received supporter_message signal for {0}'.format(supporter))
|
|
|
|
notification.send( [supporter], "wishlist_message", {'work':work, 'msg':msg}, True, sender)
|
|
from regluit.core.tasks import emit_notifications
|
|
emit_notifications.delay()
|
|
|
|
supporter_message.connect(notify_supporter_message)
|
|
|
|
def notify_join_library(sender, created, instance, **kwargs):
|
|
if created:
|
|
notification.send((instance.user, instance.library.user), "library_join", {
|
|
'library': instance.library,
|
|
'user': instance.user,
|
|
})
|
|
|
|
post_save.connect(notify_join_library, sender=LibraryUser) |