2013-06-03 16:31:39 +00:00
"""
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
2011-09-12 05:53:54 +00:00
from django . contrib . auth . models import User
2012-04-02 23:10:56 +00:00
from django . contrib . sites . models import Site
2013-06-03 16:31:39 +00:00
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
2012-04-02 23:10:56 +00:00
from django . utils . translation import ugettext_noop as _
2014-02-20 20:56:10 +00:00
from django . template . loader import render_to_string
2012-04-02 23:10:56 +00:00
from notification import models as notification
2011-09-06 03:50:38 +00:00
from social_auth . signals import pre_update
from social_auth . backends . facebook import FacebookBackend
2013-06-03 16:31:39 +00:00
"""
regluit imports
"""
2012-11-06 19:22:25 +00:00
from regluit . payment . signals import transaction_charged , transaction_failed , pledge_modified , pledge_created
2013-11-14 17:38:58 +00:00
from regluit . utils . localdatetime import now , date_today
2014-02-20 03:18:23 +00:00
from regluit . core . parameters import REWARDS , BUY2UNGLUE , THANKS , LIBRARY , RESERVE , THANKED
2013-10-31 16:26:43 +00:00
from regluit . libraryauth . models import Library , LibraryUser
2012-05-16 02:47:57 +00:00
2011-12-01 18:59:34 +00:00
logger = logging . getLogger ( __name__ )
2011-09-12 05:53:54 +00:00
2011-12-01 18:59:34 +00:00
# get email from Facebook registration
2011-09-06 03:50:38 +00:00
def facebook_extra_values ( sender , user , response , details , * * kwargs ) :
if response . get ( ' email ' ) is not None :
user . email = response . get ( ' email ' )
return True
pre_update . connect ( facebook_extra_values , sender = FacebookBackend )
2011-09-12 05:53:54 +00:00
2011-12-01 18:59:34 +00:00
# create Wishlist and UserProfile to associate with User
2011-10-24 17:36:26 +00:00
def create_user_objects ( sender , created , instance , * * kwargs ) :
2011-09-12 05:53:54 +00:00
# use get_model to avoid circular import problem with models
2012-10-31 18:08:46 +00:00
# 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 )
2013-03-04 22:01:33 +00:00
profile = UserProfile . objects . create ( user = instance )
profile . ml_subscribe ( )
2012-10-31 18:08:46 +00:00
except DatabaseError :
# this can happen when creating superuser during syncdb since the
# core_wishlist table doesn't exist yet
return
2011-09-12 05:53:54 +00:00
2011-10-24 17:36:26 +00:00
post_save . connect ( create_user_objects , sender = User )
2011-12-01 18:59:34 +00:00
# create API key for new User
2011-09-16 02:53:44 +00:00
post_save . connect ( create_api_key , sender = User )
2011-12-01 18:59:34 +00:00
2012-03-27 15:52:57 +00:00
2012-03-27 21:53:07 +00:00
# create notification types (using django-notification) -- tie to syncdb
2012-03-27 15:52:57 +00:00
def create_notice_types ( app , created_models , verbosity , * * kwargs ) :
2012-04-25 14:06:22 +00:00
notification . create_notice_type ( " comment_on_commented " , _ ( " Comment on Commented Work " ) , _ ( " A comment has been received on a book that you ' ve commented on. " ) )
2013-08-18 22:10:25 +00:00
notification . create_notice_type ( " wishlist_comment " , _ ( " Book List Comment " ) , _ ( " A comment has been received on one of your books. " ) , default = 1 )
2014-02-20 04:16:28 +00:00
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. " ) )
2012-04-25 14:06:22 +00:00
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. " ) )
2014-02-20 04:16:28 +00:00
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. " ) )
2012-04-25 14:06:22 +00:00
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 )
2014-02-20 04:16:28 +00:00
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. " ) )
2012-04-25 14:06:22 +00:00
notification . create_notice_type ( " pledge_you_have_pledged " , _ ( " Thanks For Your Pledge! " ) , _ ( " Your ungluing pledge has been entered. " ) )
2012-05-12 01:36:08 +00:00
notification . create_notice_type ( " pledge_status_change " , _ ( " Your Pledge Has Been Modified " ) , _ ( " Your ungluing pledge has been modified. " ) )
2012-04-25 14:06:22 +00:00
notification . create_notice_type ( " pledge_charged " , _ ( " Your Pledge has been Executed " ) , _ ( " You have contributed to a successful ungluing campaign. " ) )
2012-11-06 19:22:25 +00:00
notification . create_notice_type ( " pledge_failed " , _ ( " Unable to charge your credit card " ) , _ ( " A charge to your credit card did not go through. " ) )
2012-05-12 01:36:08 +00:00
notification . create_notice_type ( " rights_holder_created " , _ ( " Agreement Accepted " ) , _ ( " You have become a verified Unglue.it rights holder. " ) )
2013-11-06 19:58:50 +00:00
notification . create_notice_type ( " rights_holder_claim " , _ ( " Claim Entered " ) , _ ( " A claim has been entered. " ) )
2012-08-08 19:02:12 +00:00
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. " ) )
2013-12-13 20:15:35 +00:00
notification . create_notice_type ( " pledge_gift_credit " , _ ( " Gift Credit Balance " ) , _ ( " You have a gift credit balance " ) )
2014-02-20 04:16:28 +00:00
notification . create_notice_type ( " new_wisher " , _ ( " New wisher " ) , _ ( " Someone new has faved a book that you ' re the rightsholder for " ) )
2013-04-17 20:24:43 +00:00
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. " ) )
2013-05-20 20:58:21 +00:00
notification . create_notice_type ( " account_active " , _ ( " Credit Card Number Updated " ) , _ ( " Payment method updated. " ) , default = 1 )
2013-08-22 18:30:56 +00:00
notification . create_notice_type ( " purchase_complete " , _ ( " Your Purchase is Complete " ) , _ ( " Your Unglue.it Purchase is Complete. " ) )
2013-10-31 16:26:43 +00:00
notification . create_notice_type ( " library_borrow " , _ ( " Library eBook Borrowed. " ) , _ ( " You ' ve borrowed an ebook through a Library participating in Unglue.it " ) )
2013-11-08 17:13:34 +00:00
notification . create_notice_type ( " library_reserve " , _ ( " Library eBook Reserved. " ) , _ ( " An ebook you ' ve reserved is available. " ) )
2013-10-31 16:26:43 +00:00
notification . create_notice_type ( " library_join " , _ ( " New Library User. " ) , _ ( " A library participating in Unglue.it has added a user " ) )
2012-04-25 02:44:59 +00:00
2012-03-27 15:52:57 +00:00
signals . post_syncdb . connect ( create_notice_types , sender = notification )
2012-03-27 17:24:16 +00:00
2012-03-27 21:53:07 +00:00
# define the notifications and tie them to corresponding signals
2012-04-02 19:04:51 +00:00
from django . contrib . comments . signals import comment_was_posted
2012-04-25 02:44:59 +00:00
2012-03-27 17:24:16 +00:00
def notify_comment ( comment , request , * * kwargs ) :
2012-03-30 07:06:57 +00:00
logger . info ( ' comment %s notifying ' % comment . pk )
2012-03-29 05:21:37 +00:00
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 )
2013-03-07 20:08:21 +00:00
all_wishers = comment . content_object . wished_by ( ) . exclude ( id = comment . user . id )
other_wishers = all_wishers . exclude ( id__in = other_commenters )
2012-06-13 11:52:53 +00:00
domain = Site . objects . get_current ( ) . domain
2012-05-25 18:52:50 +00:00
if comment . content_object . last_campaign ( ) and comment . user in comment . content_object . last_campaign ( ) . managers . all ( ) :
#official
2013-03-07 20:08:21 +00:00
notification . queue ( all_wishers , " wishlist_official_comment " , { ' comment ' : comment , ' domain ' : domain } , True )
2012-05-25 18:52:50 +00:00
else :
2013-03-05 04:11:50 +00:00
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 )
2012-05-30 01:16:01 +00:00
from regluit . core . tasks import emit_notifications
2012-04-25 02:44:19 +00:00
emit_notifications . delay ( )
2012-03-30 07:06:57 +00:00
2012-03-27 17:24:16 +00:00
comment_was_posted . connect ( notify_comment )
2012-04-02 23:10:56 +00:00
# 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 ( ) )
2013-03-05 04:11:50 +00:00
notification . send ( itertools . chain ( staff , supporters ) , " wishlist_successful " , { ' campaign ' : campaign } , True )
2012-04-25 02:44:19 +00:00
from regluit . core . tasks import emit_notifications
emit_notifications . delay ( )
2012-04-02 23:10:56 +00:00
# successful_campaign -> send notices
2012-05-12 01:36:08 +00:00
successful_campaign . connect ( notify_successful_campaign )
2012-06-28 21:07:33 +00:00
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 ( ) )
2013-03-05 04:11:50 +00:00
notification . send ( itertools . chain ( staff , supporters ) , " wishlist_unsuccessful " , { ' campaign ' : campaign } , True )
2012-06-28 21:07:33 +00:00
from regluit . core . tasks import emit_notifications
emit_notifications . delay ( )
# unsuccessful_campaign -> send notices
2012-06-29 16:52:06 +00:00
unsuccessful_campaign . connect ( notify_unsuccessful_campaign )
2012-06-28 21:07:33 +00:00
2012-05-16 02:47:57 +00:00
def handle_transaction_charged ( sender , transaction = None , * * kwargs ) :
if transaction == None :
return
2013-11-12 19:58:11 +00:00
transaction . _current_total = None
2013-08-22 18:30:56 +00:00
if transaction . campaign . type is REWARDS :
notification . send ( [ transaction . user ] , " pledge_charged " , { ' transaction ' : transaction } , True )
2014-02-20 03:18:23 +00:00
elif transaction . campaign . type is BUY2UNGLUE :
2013-08-22 18:30:56 +00:00
# provision the book
Acq = get_model ( ' core ' , ' Acq ' )
2013-10-15 20:18:30 +00:00
if transaction . offer . license == LIBRARY :
library = Library . objects . get ( id = transaction . extra [ ' library_id ' ] )
2013-10-17 02:48:29 +00:00
new_acq = Acq . objects . create ( user = library . user , work = transaction . campaign . work , license = LIBRARY )
2014-03-14 16:39:49 +00:00
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 ) )
2013-11-01 20:15:01 +00:00
copies = int ( transaction . extra . get ( ' copies ' , 1 ) )
while copies > 1 :
Acq . objects . create ( user = library . user , work = transaction . campaign . work , license = LIBRARY )
copies - = 1
2013-10-15 20:18:30 +00:00
else :
new_acq = Acq . objects . create ( user = transaction . user , work = transaction . campaign . work , license = transaction . offer . license )
2013-08-22 18:30:56 +00:00
transaction . campaign . update_left ( )
notification . send ( [ transaction . user ] , " purchase_complete " , { ' transaction ' : transaction } , True )
2013-08-29 15:57:41 +00:00
from regluit . core . tasks import watermark_acq
2013-09-06 02:56:46 +00:00
watermark_acq . delay ( new_acq )
2013-11-14 17:38:58 +00:00
if transaction . campaign . cc_date < date_today ( ) :
transaction . campaign . update_status ( send_notice = True )
2014-02-20 03:18:23 +00:00
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 )
2014-02-21 20:23:56 +00:00
notification . send ( [ transaction . user ] , " purchase_complete " , { ' transaction ' : transaction } , True )
elif transaction . receipt :
from regluit . core . tasks import send_mail_task
message = render_to_string ( " notification/purchase_complete/full.txt " , { ' transaction ' : transaction , ' current_site ' : Site . objects . get_current ( ) } )
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 ( )
2012-05-16 02:47:57 +00:00
transaction_charged . connect ( handle_transaction_charged )
2012-11-06 19:22:25 +00:00
# dealing with failed transactions
def handle_transaction_failed ( sender , transaction = None , * * kwargs ) :
2014-03-14 18:28:21 +00:00
if transaction is None or transaction . campaign . type == THANKS :
# no need to nag a failed THANKS transaction
2012-11-06 19:22:25 +00:00
return
2012-11-21 19:40:19 +00:00
# window for recharging
2014-01-15 22:59:45 +00:00
recharge_deadline = transaction . campaign . deadline_or_now + datetime . timedelta ( settings . RECHARGE_WINDOW )
2012-11-21 19:40:19 +00:00
2013-03-05 04:11:50 +00:00
notification . send ( [ transaction . user ] , " pledge_failed " , {
2012-11-21 19:40:19 +00:00
' transaction ' : transaction ,
' recharge_deadline ' : recharge_deadline
2012-11-06 19:22:25 +00:00
} , True )
from regluit . core . tasks import emit_notifications
emit_notifications . delay ( )
transaction_failed . connect ( handle_transaction_failed )
2012-05-30 01:01:17 +00:00
def handle_pledge_modified ( sender , transaction = None , up_or_down = None , * * kwargs ) :
2012-05-30 01:16:01 +00:00
# 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
2012-08-31 06:50:38 +00:00
# up_or_down is 'increased', 'decreased', or 'canceled'
2012-05-30 01:16:01 +00:00
if transaction == None or up_or_down == None :
2012-05-29 12:54:57 +00:00
return
2012-10-03 12:57:24 +00:00
if up_or_down == ' canceled ' :
transaction . user . profile . reset_pledge_badge ( )
2013-03-05 04:11:50 +00:00
notification . send ( [ transaction . user ] , " pledge_status_change " , {
2012-05-29 12:54:57 +00:00
' transaction ' : transaction ,
2012-05-30 01:16:01 +00:00
' up_or_down ' : up_or_down
2012-05-29 12:54:57 +00:00
} , True )
2012-05-29 16:08:28 +00:00
from regluit . core . tasks import emit_notifications
2012-05-29 12:54:57 +00:00
emit_notifications . delay ( )
pledge_modified . connect ( handle_pledge_modified )
def handle_you_have_pledged ( sender , transaction = None , * * kwargs ) :
if transaction == None :
return
2012-10-03 12:57:24 +00:00
#give user a badge
2012-10-03 20:01:02 +00:00
if not transaction . anonymous :
2012-10-03 21:06:51 +00:00
transaction . user . profile . reset_pledge_badge ( )
2012-10-03 12:57:24 +00:00
2013-03-05 04:11:50 +00:00
notification . send ( [ transaction . user ] , " pledge_you_have_pledged " , {
2012-05-30 01:01:17 +00:00
' transaction ' : transaction
2012-05-29 12:54:57 +00:00
} , True )
2012-05-29 16:08:28 +00:00
from regluit . core . tasks import emit_notifications
2012-05-29 12:54:57 +00:00
emit_notifications . delay ( )
pledge_created . connect ( handle_you_have_pledged )
2012-08-08 19:02:12 +00:00
amazon_suspension = Signal ( providing_args = [ " campaign " ] )
2012-08-08 18:22:33 +00:00
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 ( ) )
2013-03-05 04:11:50 +00:00
notification . send ( itertools . chain ( staff , supporters ) , " wishlist_unsuccessful_amazon " , { ' campaign ' : campaign } , True )
2012-08-08 18:22:33 +00:00
from regluit . core . tasks import emit_notifications
emit_notifications . delay ( )
amazon_suspension . connect ( handle_wishlist_unsuccessful_amazon )
2012-08-31 17:41:16 +00:00
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 :
2013-03-05 04:11:50 +00:00
notification . send ( [ claim [ 0 ] . user ] , " new_wisher " , {
2012-08-31 17:41:16 +00:00
' supporter ' : supporter ,
2012-09-18 14:16:08 +00:00
' work ' : work ,
2013-03-09 18:29:03 +00:00
' base_url ' : settings . BASE_URL_SECURE ,
2012-08-31 17:41:16 +00:00
} , True )
from regluit . core . tasks import emit_notifications
emit_notifications . delay ( )
wishlist_added . connect ( handle_wishlist_added )
2012-11-16 15:24:48 +00:00
2012-11-16 16:43:00 +00:00
deadline_impending = Signal ( providing_args = [ " campaign " ] )
2012-11-16 15:24:48 +00:00
def handle_wishlist_near_deadline ( campaign , * * kwargs ) :
"""
send two groups - one the nonpledgers , one the pledgers
set the pledged flag differently in the context
"""
2012-11-16 16:43:00 +00:00
pledgers = campaign . ungluers ( ) [ ' all ' ]
nonpledgers = campaign . work . wished_by ( ) . exclude ( id__in = [ p . id for p in pledgers ] )
2012-11-16 15:24:48 +00:00
2013-03-05 04:11:50 +00:00
notification . send ( pledgers , " wishlist_near_deadline " , {
2012-11-16 15:24:48 +00:00
' campaign ' : campaign ,
2013-03-09 18:29:03 +00:00
' domain ' : settings . BASE_URL_SECURE ,
2012-11-16 15:24:48 +00:00
' pledged ' : True ,
} , True )
2012-11-16 16:43:00 +00:00
2013-03-05 04:11:50 +00:00
notification . send ( nonpledgers , " wishlist_near_deadline " , {
2012-11-16 15:24:48 +00:00
' campaign ' : campaign ,
2013-03-09 18:29:03 +00:00
' domain ' : settings . BASE_URL_SECURE ,
2012-11-16 15:24:48 +00:00
' pledged ' : False ,
} , True )
from regluit . core . tasks import emit_notifications
emit_notifications . delay ( )
2012-11-23 17:20:58 +00:00
deadline_impending . connect ( handle_wishlist_near_deadline )
2013-02-26 17:43:54 +00:00
2013-03-01 14:46:52 +00:00
supporter_message = Signal ( providing_args = [ " supporter " , " work " , " msg " ] )
2013-02-26 17:43:54 +00:00
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 ) )
2013-03-05 04:11:50 +00:00
notification . send ( [ supporter ] , " wishlist_message " , { ' work ' : work , ' msg ' : msg } , True , sender )
2013-02-26 17:43:54 +00:00
from regluit . core . tasks import emit_notifications
emit_notifications . delay ( )
supporter_message . connect ( notify_supporter_message )
2013-10-31 16:26:43 +00:00
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 )