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
import registration . signals
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 _
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-06-03 16:31:39 +00:00
from regluit . utils . localdatetime import now
2013-08-22 18:22:54 +00:00
from regluit . core . parameters import REWARDS , BUY2UNGLUE
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-05-26 21:27:10 +00:00
def handle_same_email_account ( sender , user , * * kwargs ) :
2011-12-29 04:11:13 +00:00
logger . info ( ' checking %s ' % user . username )
2012-05-26 21:27:10 +00:00
old_users = User . objects . exclude ( id = user . id ) . filter ( email = user . email )
for old_user in old_users :
# decide why there's a previous user with this email
if not old_user . is_active :
# never activated
old_user . delete ( )
elif old_user . date_joined < user . date_joined :
# attach to old account
old_user . username = user . username
old_user . password = user . password
user . delete ( )
old_user . save ( )
user = old_user
else :
# shouldn't happen; don't want to delete the user in case the user is being used for something
old_user . email = ' %s .unglue.it ' % old_user . email
registration . signals . user_activated . connect ( handle_same_email_account )
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 )
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 books. " ) )
2012-04-25 14:06:22 +00:00
notification . create_notice_type ( " wishlist_work_claimed " , _ ( " Rights Holder is Active " ) , _ ( " A rights holder has shown up for a book that you want unglued. " ) , default = 1 )
notification . create_notice_type ( " wishlist_active " , _ ( " New Campaign " ) , _ ( " A book you ' ve wishlisted 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. " ) )
2012-04-27 12:46:54 +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 like. " ) )
2012-04-25 14:06:22 +00:00
notification . create_notice_type ( " wishlist_successful " , _ ( " Successful Campaign " ) , _ ( " An ungluing campaign that you have supported or followed 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 )
2013-03-12 20:12:11 +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 on your wishlist. " ) )
2012-04-27 12:46:54 +00:00
notification . create_notice_type ( " wishlist_price_drop " , _ ( " Campaign Price Drop " ) , _ ( " An ungluing campaign you ' re interested in has a reduced target. " ) , default = 1 )
2012-05-25 20:49:45 +00:00
notification . create_notice_type ( " wishlist_unglued_book_released " , _ ( " Unglued Book! " ) , _ ( " A book you wanted 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. " ) )
2012-04-25 14:06:22 +00:00
notification . create_notice_type ( " rights_holder_claim_approved " , _ ( " Claim Accepted " ) , _ ( " A claim you ' ve entered has been accepted. " ) )
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. " ) )
2012-08-07 18:12:50 +00:00
notification . create_notice_type ( " pledge_donation_credit " , _ ( " Donation Credit Balance " ) , _ ( " You have a donation credit balance " ) )
2012-08-31 17:41:16 +00:00
notification . create_notice_type ( " new_wisher " , _ ( " New wisher " ) , _ ( " Someone new has wished for 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. " ) )
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-08-22 18:30:56 +00:00
if transaction . campaign . type is REWARDS :
notification . send ( [ transaction . user ] , " pledge_charged " , { ' transaction ' : transaction } , True )
else :
# provision the book
Acq = get_model ( ' core ' , ' Acq ' )
2013-08-27 03:56:01 +00:00
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-08-29 15:57:41 +00:00
from regluit . core . tasks import emit_notifications
2012-05-16 02:47:57 +00:00
emit_notifications . delay ( )
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 ) :
2012-11-21 19:40:19 +00:00
if transaction is None :
2012-11-06 19:22:25 +00:00
return
2012-11-21 19:40:19 +00:00
# window for recharging
recharge_deadline = transaction . campaign . deadline + datetime . timedelta ( settings . RECHARGE_WINDOW )
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 ) )
site = Site . objects . get_current ( )
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 )