2010-06-30 13:36:51 -04:00
import datetime
2013-03-20 18:36:15 -07:00
import hashlib
2015-08-26 10:58:05 -07:00
import re
2024-04-24 09:50:42 -04:00
import time
2015-06-30 16:05:58 -07:00
import uuid
2024-04-24 09:50:42 -04:00
from wsgiref . util import application_uri
import dateutil
2012-07-09 13:55:29 -07:00
import mongoengine as mongo
2024-04-24 09:50:42 -04:00
import paypalrestsdk
import redis
import stripe
2011-09-19 08:56:16 -07:00
from django . conf import settings
2010-11-08 12:09:55 -05:00
from django . contrib . auth import authenticate
2011-09-19 08:56:16 -07:00
from django . contrib . auth . models import User
2022-02-16 09:20:43 -05:00
from django . contrib . sites . models import Site
2024-04-24 09:50:42 -04:00
from django . core . mail import EmailMultiAlternatives , mail_admins
from django . db import IntegrityError , models
from django . db . models import Avg , Count , Q , Sum
from django . db . models . signals import post_save
from django . db . utils import DatabaseError
2011-09-19 08:56:16 -07:00
from django . template . loader import render_to_string
2024-04-24 09:50:42 -04:00
from django . urls import reverse
from paypal . standard . ipn . models import PayPalIPN
from paypal . standard . ipn . signals import invalid_ipn_received , valid_ipn_received
from zebra . signals import (
zebra_webhook_charge_refunded ,
zebra_webhook_charge_succeeded ,
zebra_webhook_checkout_session_completed ,
zebra_webhook_customer_subscription_created ,
zebra_webhook_customer_subscription_updated ,
)
2020-06-15 17:53:35 -04:00
from apps . feed_import . models import OPMLExporter
2024-04-24 09:50:42 -04:00
from apps . reader . models import RUserStory , UserSubscription
from apps . rss_feeds . models import Feed , MStarredStory , MStory
from apps . rss_feeds . tasks import SchedulePremiumSetup
2012-07-13 18:42:44 -07:00
from utils import json_functions as json
2024-04-24 09:50:42 -04:00
from utils import log as logging
2015-07-28 18:46:37 -07:00
from utils . feed_functions import chunks
2024-04-24 09:50:42 -04:00
from utils . user_functions import generate_secret_token
2011-09-19 08:56:16 -07:00
from vendor . timezones . fields import TimeZoneField
2024-04-24 09:43:56 -04:00
2010-05-11 21:36:17 -04:00
class Profile ( models . Model ) :
2024-04-24 09:43:56 -04:00
user = models . OneToOneField ( User , unique = True , related_name = " profile " , on_delete = models . CASCADE )
is_premium = models . BooleanField ( default = False )
is_archive = models . BooleanField ( default = False , blank = True , null = True )
is_pro = models . BooleanField ( default = False , blank = True , null = True )
premium_expire = models . DateTimeField ( blank = True , null = True )
send_emails = models . BooleanField ( default = True )
preferences = models . TextField ( default = " {} " )
view_settings = models . TextField ( default = " {} " )
2010-09-05 18:08:08 -07:00
collapsed_folders = models . TextField ( default = " [] " )
2024-04-24 09:43:56 -04:00
feed_pane_size = models . IntegerField ( default = 282 )
days_of_unread = models . IntegerField ( default = settings . DAYS_OF_UNREAD , blank = True , null = True )
2012-03-20 11:15:40 -07:00
tutorial_finished = models . BooleanField ( default = False )
2020-12-09 17:20:08 -05:00
hide_getting_started = models . BooleanField ( default = False , null = True , blank = True )
2024-04-24 09:43:56 -04:00
has_setup_feeds = models . BooleanField ( default = False , null = True , blank = True )
2020-12-09 17:20:08 -05:00
has_found_friends = models . BooleanField ( default = False , null = True , blank = True )
has_trained_intelligence = models . BooleanField ( default = False , null = True , blank = True )
2024-04-24 09:43:56 -04:00
last_seen_on = models . DateTimeField ( default = datetime . datetime . now )
last_seen_ip = models . CharField ( max_length = 50 , blank = True , null = True )
dashboard_date = models . DateTimeField ( default = datetime . datetime . now )
timezone = TimeZoneField ( default = " America/New_York " )
secret_token = models . CharField ( max_length = 12 , blank = True , null = True )
stripe_4_digits = models . CharField ( max_length = 4 , blank = True , null = True )
stripe_id = models . CharField ( max_length = 24 , blank = True , null = True )
paypal_sub_id = models . CharField ( max_length = 24 , blank = True , null = True )
2022-02-08 12:49:40 -05:00
# paypal_payer_id = models.CharField(max_length=24, blank=True, null=True)
2024-04-24 09:43:56 -04:00
premium_renewal = models . BooleanField ( default = False , blank = True , null = True )
active_provider = models . CharField ( max_length = 24 , blank = True , null = True )
2020-06-30 20:50:30 -04:00
def __str__ ( self ) :
2022-01-11 10:59:45 -05:00
return " %s < %s > %s %s %s " % (
2024-04-24 09:43:56 -04:00
self . user ,
self . user . email ,
" (Premium) " if self . is_premium and not self . is_archive and not self . is_pro else " " ,
2022-01-11 10:59:45 -05:00
" (Premium ARCHIVE) " if self . is_archive and not self . is_pro else " " ,
" (Premium PRO) " if self . is_pro else " " ,
2022-01-10 16:07:49 -05:00
)
2024-04-24 09:43:56 -04:00
2022-01-24 17:23:25 -05:00
@classmethod
def plan_to_stripe_price ( cls , plan ) :
price = None
if plan == " premium " :
price = " newsblur-premium-36 "
elif plan == " archive " :
price = " price_0KK5a7wdsmP8XBlaHfbQNnaL "
if settings . DEBUG :
price = " price_0KK5tVwdsmP8XBlaXW1vYUn9 "
elif plan == " pro " :
price = " price_0KK5cvwdsmP8XBlaZDq068bA "
if settings . DEBUG :
price = " price_0KK5twwdsmP8XBlasifbX56Z "
return price
2024-04-24 09:43:56 -04:00
2022-02-04 17:10:23 -05:00
@classmethod
2022-02-16 09:20:43 -05:00
def plan_to_paypal_plan_id ( cls , plan ) :
price = None
if plan == " premium " :
price = " P-48R22630SD810553FMHZONIY "
if settings . DEBUG :
price = " P-4RV31836YD8080909MHZROJY "
elif plan == " archive " :
price = " P-5JM46230U31841226MHZOMZY "
if settings . DEBUG :
price = " P-2EG40290653242115MHZROQQ "
2022-11-26 09:20:37 -05:00
elif plan == " pro " :
price = " price_0KK5cvwdsmP8XBlaZDq068bA "
if settings . DEBUG :
price = " price_0KK5twwdsmP8XBlasifbX56Z "
2022-02-16 09:20:43 -05:00
return price
2022-02-04 17:10:23 -05:00
2013-09-16 16:42:49 -07:00
@property
2022-01-13 14:55:44 -05:00
def unread_cutoff ( self , force_premium = False , force_archive = False ) :
if self . is_archive or force_archive :
2022-02-16 15:46:44 -05:00
days_of_unread = self . days_of_unread or settings . DAYS_OF_UNREAD
return datetime . datetime . utcnow ( ) - datetime . timedelta ( days = days_of_unread )
2013-10-07 10:02:44 -07:00
if self . is_premium or force_premium :
2013-09-16 16:42:49 -07:00
return datetime . datetime . utcnow ( ) - datetime . timedelta ( days = settings . DAYS_OF_UNREAD )
2024-04-24 09:43:56 -04:00
2013-09-16 16:42:49 -07:00
return datetime . datetime . utcnow ( ) - datetime . timedelta ( days = settings . DAYS_OF_UNREAD_FREE )
2013-10-07 10:02:44 -07:00
@property
def unread_cutoff_premium ( self ) :
return datetime . datetime . utcnow ( ) - datetime . timedelta ( days = settings . DAYS_OF_UNREAD )
2024-04-24 09:43:56 -04:00
2022-01-13 14:55:44 -05:00
@property
def days_of_story_hashes ( self ) :
if self . is_archive :
return settings . DAYS_OF_STORY_HASHES_ARCHIVE
return settings . DAYS_OF_STORY_HASHES
2013-06-12 13:52:43 -07:00
def canonical ( self ) :
2012-07-13 18:42:44 -07:00
return {
2024-04-24 09:43:56 -04:00
" is_premium " : self . is_premium ,
" is_archive " : self . is_archive ,
" is_pro " : self . is_pro ,
" premium_expire " : int ( self . premium_expire . strftime ( " %s " ) ) if self . premium_expire else 0 ,
" preferences " : json . decode ( self . preferences ) ,
" tutorial_finished " : self . tutorial_finished ,
" hide_getting_started " : self . hide_getting_started ,
" has_setup_feeds " : self . has_setup_feeds ,
" has_found_friends " : self . has_found_friends ,
" has_trained_intelligence " : self . has_trained_intelligence ,
" dashboard_date " : self . dashboard_date ,
2012-07-13 18:42:44 -07:00
}
2024-04-24 09:43:56 -04:00
2011-01-20 09:57:23 -05:00
def save ( self , * args , * * kwargs ) :
if not self . secret_token :
self . secret_token = generate_secret_token ( self . user . username , 12 )
2011-07-17 20:53:30 -07:00
try :
super ( Profile , self ) . save ( * args , * * kwargs )
2022-02-16 15:40:51 -05:00
except DatabaseError as e :
print ( f " ---> Profile not saved: { e } " )
2024-04-24 09:43:56 -04:00
2014-06-16 15:01:05 -07:00
def delete_user ( self , confirm = False , fast = False ) :
2012-07-28 18:33:07 -07:00
if not confirm :
2020-06-17 00:17:32 -04:00
print ( " ---> You must pass confirm=True to delete this user. " )
2012-07-28 18:33:07 -07:00
return
2024-04-24 09:43:56 -04:00
2015-11-23 11:22:00 -08:00
logging . user ( self . user , " Deleting user: %s / %s " % ( self . user . email , self . user . profile . last_seen_ip ) )
2014-04-03 14:59:30 -07:00
try :
2022-06-06 11:52:16 -04:00
if not fast :
self . cancel_premium ( )
2014-04-03 14:59:30 -07:00
except :
logging . user ( self . user , " ~BR~SK~FWError cancelling premium renewal for: %s " % self . user . username )
2024-04-24 09:43:56 -04:00
2024-04-24 09:50:42 -04:00
from apps . social . models import (
MActivity ,
MInteraction ,
MSharedStory ,
MSocialProfile ,
MSocialSubscription ,
)
2024-04-24 09:43:56 -04:00
2012-07-29 23:53:02 -07:00
try :
social_profile = MSocialProfile . objects . get ( user_id = self . user . pk )
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" Unfollowing %s followings and %s followers "
% ( social_profile . following_count , social_profile . follower_count ) ,
)
2012-07-29 23:53:02 -07:00
for follow in social_profile . following_user_ids :
social_profile . unfollow_user ( follow )
for follower in social_profile . follower_user_ids :
follower_profile = MSocialProfile . objects . get ( user_id = follower )
follower_profile . unfollow_user ( self . user . pk )
social_profile . delete ( )
2020-01-18 14:37:44 -05:00
except ( MSocialProfile . DoesNotExist , IndexError ) :
2013-01-03 10:33:22 -08:00
logging . user ( self . user , " ***> No social profile found. S ' ok, moving on. " )
2012-07-29 23:53:02 -07:00
pass
2024-04-24 09:43:56 -04:00
2012-07-28 18:33:07 -07:00
shared_stories = MSharedStory . objects . filter ( user_id = self . user . pk )
2013-01-03 10:33:22 -08:00
logging . user ( self . user , " Deleting %s shared stories " % shared_stories . count ( ) )
2012-07-28 18:33:07 -07:00
for story in shared_stories :
2012-10-25 14:18:25 -07:00
try :
2014-06-16 15:01:05 -07:00
if not fast :
original_story = MStory . objects . get ( story_hash = story . story_hash )
original_story . sync_redis ( )
2012-10-25 14:18:25 -07:00
except MStory . DoesNotExist :
pass
2012-07-28 18:33:07 -07:00
story . delete ( )
2024-04-24 09:43:56 -04:00
2012-07-28 18:33:07 -07:00
subscriptions = MSocialSubscription . objects . filter ( subscription_user_id = self . user . pk )
2013-01-03 10:33:22 -08:00
logging . user ( self . user , " Deleting %s social subscriptions " % subscriptions . count ( ) )
2012-07-28 18:33:07 -07:00
subscriptions . delete ( )
2024-04-24 09:43:56 -04:00
2012-07-28 18:33:07 -07:00
interactions = MInteraction . objects . filter ( user_id = self . user . pk )
2013-01-03 10:33:22 -08:00
logging . user ( self . user , " Deleting %s interactions for user. " % interactions . count ( ) )
2012-07-28 18:33:07 -07:00
interactions . delete ( )
2024-04-24 09:43:56 -04:00
2012-07-28 18:33:07 -07:00
interactions = MInteraction . objects . filter ( with_user_id = self . user . pk )
2013-01-03 10:33:22 -08:00
logging . user ( self . user , " Deleting %s interactions with user. " % interactions . count ( ) )
2012-07-28 18:33:07 -07:00
interactions . delete ( )
2024-04-24 09:43:56 -04:00
2012-07-28 18:33:07 -07:00
activities = MActivity . objects . filter ( user_id = self . user . pk )
2013-01-03 10:33:22 -08:00
logging . user ( self . user , " Deleting %s activities for user. " % activities . count ( ) )
2012-07-28 18:33:07 -07:00
activities . delete ( )
2024-04-24 09:43:56 -04:00
2012-07-28 18:33:07 -07:00
activities = MActivity . objects . filter ( with_user_id = self . user . pk )
2013-01-03 10:33:22 -08:00
logging . user ( self . user , " Deleting %s activities with user. " % activities . count ( ) )
2012-07-28 18:33:07 -07:00
activities . delete ( )
2024-04-24 09:43:56 -04:00
2013-07-11 15:55:37 -07:00
starred_stories = MStarredStory . objects . filter ( user_id = self . user . pk )
logging . user ( self . user , " Deleting %s starred stories. " % starred_stories . count ( ) )
starred_stories . delete ( )
2024-04-24 09:43:56 -04:00
2022-06-21 11:23:25 -04:00
paypal_ids = PaypalIds . objects . filter ( user = self . user )
logging . user ( self . user , " Deleting %s PayPal IDs. " % paypal_ids . count ( ) )
paypal_ids . delete ( )
2024-04-24 09:43:56 -04:00
2022-06-21 11:23:25 -04:00
stripe_ids = StripeIds . objects . filter ( user = self . user )
logging . user ( self . user , " Deleting %s Stripe IDs. " % stripe_ids . count ( ) )
stripe_ids . delete ( )
2024-04-24 09:43:56 -04:00
2013-01-03 10:33:22 -08:00
logging . user ( self . user , " Deleting user: %s " % self . user )
2012-07-28 18:33:07 -07:00
self . user . delete ( )
2024-04-24 09:43:56 -04:00
2022-02-17 12:27:49 -05:00
def activate_premium ( self , never_expire = False ) :
2012-07-05 22:20:49 -07:00
from apps . profile . tasks import EmailNewPremium
2024-04-24 09:43:56 -04:00
2021-01-19 17:33:20 -05:00
EmailNewPremium . delay ( user_id = self . user . pk )
2023-07-20 21:06:39 -04:00
subs = UserSubscription . objects . filter ( user = self . user )
2023-07-21 13:52:43 -04:00
if subs . count ( ) > 5000 :
2023-07-20 21:06:39 -04:00
logging . user ( self . user , " ~FR~SK~FW~SBWARNING! ~FR %s subscriptions~SN! " % ( subs . count ( ) ) )
2024-04-24 09:43:56 -04:00
mail_admins (
f " WARNING! { self . user . username } has { subs . count ( ) } subscriptions " ,
f " { self . user . username } has { subs . count ( ) } subscriptions and just upgraded to premium. They ' ll need a refund: { self . user . profile . paypal_sub_id } { self . user . profile . stripe_id } { self . user . email } " ,
)
2023-07-20 21:06:39 -04:00
return False
2024-04-24 09:43:56 -04:00
2018-07-20 15:55:15 -04:00
was_premium = self . is_premium
2010-10-23 11:20:54 -04:00
self . is_premium = True
2022-02-17 12:27:49 -05:00
self . is_archive = False
self . is_pro = False
2010-10-23 11:20:54 -04:00
self . save ( )
2013-05-13 18:03:17 -07:00
self . user . is_active = True
self . user . save ( )
2024-04-24 09:43:56 -04:00
2018-07-20 15:55:15 -04:00
# Only auto-enable every feed if a free user is moving to premium
if not was_premium :
for sub in subs :
2024-04-24 09:43:56 -04:00
if sub . active :
continue
2018-07-20 15:55:15 -04:00
sub . active = True
try :
sub . save ( )
except ( IntegrityError , Feed . DoesNotExist ) :
pass
2024-04-24 09:43:56 -04:00
2018-07-23 10:39:11 -04:00
try :
scheduled_feeds = [ sub . feed . pk for sub in subs ]
except Feed . DoesNotExist :
scheduled_feeds = [ ]
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~SN~FMTasking the scheduling immediate premium setup of ~SB %s ~SN feeds... "
% len ( scheduled_feeds ) ,
)
2021-01-06 14:42:24 -05:00
SchedulePremiumSetup . apply_async ( kwargs = dict ( feed_ids = scheduled_feeds ) )
2024-04-24 09:43:56 -04:00
2018-07-23 10:39:11 -04:00
UserSubscription . queue_new_feeds ( self . user )
2024-04-24 09:43:56 -04:00
2022-02-16 17:11:08 -05:00
# self.setup_premium_history() # Let's not call this unnecessarily
2024-04-24 09:43:56 -04:00
2015-05-18 17:27:24 -07:00
if never_expire :
self . premium_expire = None
self . save ( )
2022-04-08 16:08:06 -04:00
if not was_premium :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BY~SK~FW~SBNEW PREMIUM ACCOUNT! WOOHOO!!! ~FR %s subscriptions~SN! " % ( subs . count ( ) ) ,
)
2013-05-10 12:05:24 -07:00
return True
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
def activate_archive ( self , never_expire = False ) :
2022-04-18 13:29:13 -04:00
UserSubscription . schedule_fetch_archive_feeds_for_user ( self . user . pk )
2024-04-24 09:43:56 -04:00
2023-07-20 22:15:25 -04:00
subs = UserSubscription . objects . filter ( user = self . user )
2023-07-21 13:52:43 -04:00
if subs . count ( ) > 2000 :
2023-07-20 22:15:25 -04:00
logging . user ( self . user , " ~FR~SK~FW~SBWARNING! ~FR %s subscriptions~SN! " % ( subs . count ( ) ) )
2024-04-24 09:43:56 -04:00
mail_admins (
f " WARNING! { self . user . username } has { subs . count ( ) } subscriptions " ,
f " { self . user . username } has { subs . count ( ) } subscriptions and just upgraded to archive. They ' ll need a refund: { self . user . profile . paypal_sub_id } { self . user . profile . stripe_id } { self . user . email } " ,
)
2023-07-20 22:15:25 -04:00
return False
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
was_premium = self . is_premium
was_archive = self . is_archive
was_pro = self . is_pro
self . is_premium = True
self . is_archive = True
self . save ( )
self . user . is_active = True
self . user . save ( )
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
# Only auto-enable every feed if a free user is moving to premium
if not was_premium :
for sub in subs :
2024-04-24 09:43:56 -04:00
if sub . active :
continue
2022-01-11 13:43:38 -05:00
sub . active = True
try :
sub . save ( )
except ( IntegrityError , Feed . DoesNotExist ) :
pass
2024-04-24 09:43:56 -04:00
2022-04-18 13:29:13 -04:00
# Count subscribers to turn on archive_subscribers counts, then show that count to users
# on the paypal_archive_return page.
2022-01-11 13:43:38 -05:00
try :
scheduled_feeds = [ sub . feed . pk for sub in subs ]
except Feed . DoesNotExist :
scheduled_feeds = [ ]
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~SN~FMTasking the scheduling immediate premium setup of ~SB %s ~SN feeds... "
% len ( scheduled_feeds ) ,
)
2022-01-11 13:43:38 -05:00
SchedulePremiumSetup . apply_async ( kwargs = dict ( feed_ids = scheduled_feeds ) )
2022-04-18 13:29:13 -04:00
2022-01-11 13:43:38 -05:00
UserSubscription . queue_new_feeds ( self . user )
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
self . setup_premium_history ( )
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
if never_expire :
self . premium_expire = None
self . save ( )
2022-04-08 16:08:06 -04:00
if not was_archive :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BY~SK~FW~SBNEW PREMIUM ~BBARCHIVE~BY ACCOUNT! WOOHOO!!! ~FR %s subscriptions~SN! "
% ( subs . count ( ) ) ,
)
2022-01-11 13:43:38 -05:00
return True
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
def activate_pro ( self , never_expire = False ) :
from apps . profile . tasks import EmailNewPremiumPro
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
EmailNewPremiumPro . delay ( user_id = self . user . pk )
2024-04-24 09:43:56 -04:00
2023-07-20 22:15:25 -04:00
subs = UserSubscription . objects . filter ( user = self . user )
2023-07-21 13:52:43 -04:00
if subs . count ( ) > 1000 :
2023-07-20 22:15:25 -04:00
logging . user ( self . user , " ~FR~SK~FW~SBWARNING! ~FR %s subscriptions~SN! " % ( subs . count ( ) ) )
2024-04-24 09:43:56 -04:00
mail_admins (
f " WARNING! { self . user . username } has { subs . count ( ) } subscriptions " ,
f " { self . user . username } has { subs . count ( ) } subscriptions and just upgraded to pro. They ' ll need a refund: { self . user . profile . paypal_sub_id } { self . user . profile . stripe_id } { self . user . email } " ,
)
2023-07-20 22:15:25 -04:00
return False
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
was_premium = self . is_premium
was_archive = self . is_archive
was_pro = self . is_pro
self . is_premium = True
self . is_archive = True
self . is_pro = True
self . save ( )
self . user . is_active = True
self . user . save ( )
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
# Only auto-enable every feed if a free user is moving to premium
if not was_premium :
for sub in subs :
2024-04-24 09:43:56 -04:00
if sub . active :
continue
2022-01-11 13:43:38 -05:00
sub . active = True
try :
sub . save ( )
except ( IntegrityError , Feed . DoesNotExist ) :
pass
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
try :
scheduled_feeds = [ sub . feed . pk for sub in subs ]
except Feed . DoesNotExist :
scheduled_feeds = [ ]
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~SN~FMTasking the scheduling immediate premium setup of ~SB %s ~SN feeds... "
% len ( scheduled_feeds ) ,
)
2022-01-11 13:43:38 -05:00
SchedulePremiumSetup . apply_async ( kwargs = dict ( feed_ids = scheduled_feeds ) )
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
UserSubscription . queue_new_feeds ( self . user )
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
self . setup_premium_history ( )
2024-04-24 09:43:56 -04:00
2022-01-11 13:43:38 -05:00
if never_expire :
self . premium_expire = None
self . save ( )
2022-04-08 16:08:06 -04:00
if not was_pro :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BY~SK~FW~SBNEW PREMIUM ~BGPRO~BY ACCOUNT! WOOHOO!!! ~FR %s subscriptions~SN! "
% ( subs . count ( ) ) ,
)
2022-01-11 13:43:38 -05:00
return True
2024-04-24 09:43:56 -04:00
2012-12-05 13:10:11 -08:00
def deactivate_premium ( self ) :
self . is_premium = False
2022-01-11 15:56:19 -05:00
self . is_pro = False
self . is_archive = False
2012-12-05 13:10:11 -08:00
self . save ( )
2024-04-24 09:43:56 -04:00
2012-12-05 13:10:11 -08:00
subs = UserSubscription . objects . filter ( user = self . user )
for sub in subs :
sub . active = False
try :
sub . save ( )
2015-05-18 14:45:00 -07:00
# Don't bother recalculating feed's subs, as it will do that on next fetch
# sub.feed.setup_feed_for_premium_subscribers()
2013-05-10 12:05:24 -07:00
except ( IntegrityError , Feed . DoesNotExist ) :
2012-12-05 13:10:11 -08:00
pass
2024-04-24 09:43:56 -04:00
logging . user (
self . user , " ~BY~FW~SBBOO! Deactivating premium account: ~FR %s subscriptions~SN! " % ( subs . count ( ) )
)
2013-05-13 18:03:17 -07:00
def activate_free ( self ) :
if self . user . is_active :
return
2024-04-24 09:43:56 -04:00
2013-05-13 18:03:17 -07:00
self . user . is_active = True
self . user . save ( )
self . send_new_user_queue_email ( )
2024-04-24 09:43:56 -04:00
2022-02-16 09:20:43 -05:00
def paypal_change_billing_details_url ( self ) :
return " https://paypal.com "
2024-04-24 09:43:56 -04:00
2022-02-16 09:20:43 -05:00
def switch_stripe_subscription ( self , plan ) :
2022-01-25 17:26:24 -05:00
stripe_customer = self . stripe_customer ( )
if not stripe_customer :
return
2024-04-24 09:43:56 -04:00
2022-01-25 17:26:24 -05:00
stripe_subscriptions = stripe . Subscription . list ( customer = stripe_customer . id ) . data
existing_subscription = None
for subscription in stripe_subscriptions :
if subscription . plan . active :
existing_subscription = subscription
break
2024-04-24 09:43:56 -04:00
if not existing_subscription :
2022-01-25 17:26:24 -05:00
return
2022-07-01 12:20:10 -04:00
try :
stripe . Subscription . modify (
existing_subscription . id ,
cancel_at_period_end = False ,
2024-04-24 09:43:56 -04:00
proration_behavior = " always_invoice " ,
items = [
{
" id " : existing_subscription [ " items " ] [ " data " ] [ 0 ] . id ,
" price " : Profile . plan_to_stripe_price ( plan ) ,
}
] ,
2022-07-01 12:20:10 -04:00
)
except stripe . error . CardError as e :
logging . user ( self . user , f " ~FRStripe switch subscription failed: ~SB { e } " )
return
2024-04-24 09:43:56 -04:00
2022-01-25 17:26:24 -05:00
self . setup_premium_history ( )
2024-04-24 09:43:56 -04:00
2022-02-16 13:43:53 -05:00
return True
2022-04-08 15:07:58 -04:00
def cancel_and_prorate_existing_paypal_subscriptions ( self , data ) :
paypal_api = self . paypal_api ( )
if not paypal_api :
return
2024-04-24 09:43:56 -04:00
2022-04-08 15:07:58 -04:00
canceled_paypal_sub_id = self . cancel_premium_paypal ( cancel_older_subscriptions_only = True )
if not canceled_paypal_sub_id :
logging . user ( self . user , f " ~FRCould not cancel and prorate older paypal premium: { data } " )
return
if isinstance ( canceled_paypal_sub_id , str ) :
self . refund_paypal_payment_from_subscription ( canceled_paypal_sub_id , prorate = True )
2022-02-16 17:11:08 -05:00
def switch_paypal_subscription_approval_url ( self , plan ) :
2022-02-16 09:20:43 -05:00
paypal_api = self . paypal_api ( )
if not paypal_api :
return
2024-04-24 09:43:56 -04:00
paypal_return = reverse ( " paypal-return " )
2022-04-06 15:56:13 -04:00
if plan == " archive " :
2024-04-24 09:43:56 -04:00
paypal_return = reverse ( " paypal-archive-return " )
2022-04-06 15:56:13 -04:00
2022-02-16 09:20:43 -05:00
try :
2022-04-06 15:56:13 -04:00
application_context = {
2024-04-24 09:43:56 -04:00
" shipping_preference " : " NO_SHIPPING " ,
" user_action " : " SUBSCRIBE_NOW " ,
2022-04-06 15:56:13 -04:00
}
if settings . DEBUG :
2024-04-24 09:43:56 -04:00
application_context [ " return_url " ] = f " https://a6d3-161-77-224-226.ngrok.io { paypal_return } "
2022-04-06 15:56:13 -04:00
else :
2024-04-24 09:43:56 -04:00
application_context [
" return_url "
] = f " https:// { Site . objects . get_current ( ) . domain } { paypal_return } "
paypal_subscription = paypal_api . post (
f " /v1/billing/subscriptions " ,
{
" plan_id " : Profile . plan_to_paypal_plan_id ( plan ) ,
" custom_id " : self . user . pk ,
" application_context " : application_context ,
} ,
)
2022-04-08 15:07:58 -04:00
except paypalrestsdk . ResourceNotFound as e :
2024-04-24 09:43:56 -04:00
logging . user (
self . user , f " ~FRCouldn ' t create paypal subscription: { self . paypal_sub_id } { plan } : { e } "
)
2022-02-16 09:20:43 -05:00
paypal_subscription = None
if not paypal_subscription :
return
logging . user ( self . user , paypal_subscription )
2024-04-24 09:43:56 -04:00
for link in paypal_subscription . get ( " links " , [ ] ) :
if link [ " rel " ] == " approve " :
return link [ " href " ]
2022-02-16 09:20:43 -05:00
logging . user ( self . user , f " ~FRFailed to switch paypal subscription: ~FC { paypal_subscription } " )
2022-04-08 15:07:58 -04:00
def store_paypal_sub_id ( self , paypal_sub_id , skip_save_primary = False ) :
2022-02-08 20:56:23 -05:00
if not paypal_sub_id :
logging . user ( self . user , " ~FBPaypal sub id not found, ignoring " )
return
2022-04-08 15:07:58 -04:00
if not skip_save_primary or not self . paypal_sub_id :
self . paypal_sub_id = paypal_sub_id
self . save ( )
2024-04-24 09:43:56 -04:00
2022-02-08 20:56:23 -05:00
seen_paypal_ids = set ( p . paypal_sub_id for p in self . user . paypal_ids . all ( ) )
if paypal_sub_id in seen_paypal_ids :
logging . user ( self . user , f " ~FBPaypal sub seen before, ignoring: { paypal_sub_id } " )
return
2024-04-24 09:43:56 -04:00
2022-02-08 20:56:23 -05:00
self . user . paypal_ids . create ( paypal_sub_id = paypal_sub_id )
logging . user ( self . user , f " ~FBPaypal sub ~SBadded~SN: ~SB { paypal_sub_id } " )
2019-09-09 21:17:10 -04:00
def setup_premium_history ( self , alt_email = None , set_premium_expire = True , force_expiration = False ) :
2014-11-17 13:54:39 -08:00
stripe_payments = [ ]
2018-05-07 13:10:27 -07:00
total_stripe_payments = 0
2022-02-08 12:49:40 -05:00
total_paypal_payments = 0
2022-01-25 17:26:24 -05:00
active_plan = None
premium_renewal = False
2022-02-16 09:20:43 -05:00
active_provider = None
2024-04-24 09:43:56 -04:00
2022-02-08 12:49:40 -05:00
# Find modern Paypal payments
2022-02-08 18:40:07 -05:00
self . retrieve_paypal_ids ( )
2022-02-08 12:49:40 -05:00
if self . paypal_sub_id :
seen_payments = set ( )
2022-06-05 14:16:52 -04:00
seen_payment_history = PaymentHistory . objects . filter ( user = self . user , payment_provider = " paypal " )
2022-06-05 14:14:01 -04:00
deleted_paypal_payments = 0
for payment in list ( seen_payment_history ) :
2022-06-05 12:47:57 -04:00
if payment . payment_date . date ( ) in seen_payments :
payment . delete ( )
2022-06-05 14:14:01 -04:00
deleted_paypal_payments + = 1
2022-06-05 12:47:57 -04:00
else :
seen_payments . add ( payment . payment_date . date ( ) )
2022-06-05 13:34:58 -04:00
total_paypal_payments + = 1
2022-06-05 14:14:01 -04:00
if deleted_paypal_payments > 0 :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
f " ~BY~SN~FRDeleting~FW duplicate paypal history: ~SB { deleted_paypal_payments } payments " ,
)
2022-02-09 12:26:35 -05:00
paypal_api = self . paypal_api ( )
2022-02-08 20:56:23 -05:00
for paypal_id_model in self . user . paypal_ids . all ( ) :
2022-02-09 12:26:35 -05:00
paypal_id = paypal_id_model . paypal_sub_id
2022-02-08 20:56:23 -05:00
try :
2024-04-24 09:43:56 -04:00
paypal_subscription = paypal_api . get ( f " /v1/billing/subscriptions/ { paypal_id } ?fields=plan " )
2022-02-08 20:56:23 -05:00
except paypalrestsdk . ResourceNotFound :
logging . user ( self . user , f " ~FRCouldn ' t find paypal payments: { paypal_id } " )
2022-02-09 12:26:35 -05:00
paypal_subscription = None
2022-02-08 12:49:40 -05:00
2022-02-08 20:56:23 -05:00
if paypal_subscription :
2024-04-24 09:43:56 -04:00
if paypal_subscription [ " status " ] in [ " APPROVAL_PENDING " , " APPROVED " , " ACTIVE " ] :
active_plan = paypal_subscription . get ( " plan_id " , None )
2022-07-02 10:53:24 -04:00
if not active_plan :
2024-04-24 09:43:56 -04:00
active_plan = paypal_subscription [ " plan " ] [ " name " ]
2022-02-16 09:20:43 -05:00
active_provider = " paypal "
2022-02-08 20:56:23 -05:00
premium_renewal = True
2022-02-08 12:49:40 -05:00
2022-06-05 09:46:27 -04:00
start_date = datetime . datetime ( 2009 , 1 , 1 ) . strftime ( " % Y- % m- %d T % H: % M: % S.000Z " )
end_date = datetime . datetime . now ( ) . strftime ( " % Y- % m- %d T % H: % M: % S.000Z " )
2022-04-06 15:56:13 -04:00
try :
2024-04-24 09:43:56 -04:00
transactions = paypal_api . get (
f " /v1/billing/subscriptions/ { paypal_id } /transactions?start_time= { start_date } &end_time= { end_date } "
)
2022-04-06 15:56:13 -04:00
except paypalrestsdk . exceptions . ResourceNotFound :
transactions = None
2024-04-24 09:43:56 -04:00
if not transactions or " transactions " not in transactions :
2022-04-06 15:56:13 -04:00
logging . user ( self . user , f " ~FRCouldn ' t find paypal transactions: ~SB { paypal_id } " )
2022-02-08 21:16:12 -05:00
continue
2024-04-24 09:43:56 -04:00
for transaction in transactions [ " transactions " ] :
created = dateutil . parser . parse ( transaction [ " time " ] ) . date ( )
if transaction [ " status " ] not in [ " COMPLETED " , " PARTIALLY_REFUNDED " , " REFUNDED " ] :
continue
if created in seen_payments :
continue
2022-02-08 20:56:23 -05:00
seen_payments . add ( created )
total_paypal_payments + = 1
2022-04-08 15:07:58 -04:00
refunded = None
2024-04-24 09:43:56 -04:00
if transaction [ " status " ] in [ " PARTIALLY_REFUNDED " , " REFUNDED " ] :
2022-04-08 15:07:58 -04:00
refunded = True
2024-04-24 09:43:56 -04:00
PaymentHistory . objects . get_or_create (
user = self . user ,
payment_date = created ,
payment_amount = int (
float ( transaction [ " amount_with_breakdown " ] [ " gross_amount " ] [ " value " ] )
) ,
payment_provider = " paypal " ,
refunded = refunded ,
)
ipns = PayPalIPN . objects . filter (
Q ( custom = self . user . username ) | Q ( payer_email = self . user . email ) | Q ( custom = self . user . pk )
) . order_by ( " -payment_date " )
2022-06-05 12:19:49 -04:00
for transaction in ipns :
2022-06-05 12:45:17 -04:00
if transaction . txn_type != " subscr_payment " :
continue
2022-06-05 12:19:49 -04:00
created = transaction . payment_date . date ( )
2024-04-24 09:43:56 -04:00
if created in seen_payments :
2022-06-05 12:45:17 -04:00
continue
2022-06-05 12:19:49 -04:00
seen_payments . add ( created )
total_paypal_payments + = 1
2024-04-24 09:43:56 -04:00
PaymentHistory . objects . get_or_create (
user = self . user ,
payment_date = created ,
payment_amount = int ( transaction . payment_gross ) ,
payment_provider = " paypal " ,
)
2022-02-08 18:40:07 -05:00
else :
logging . user ( self . user , " ~FBNo Paypal payments " )
2024-04-24 09:43:56 -04:00
2012-12-03 14:35:21 -08:00
# Record Stripe payments
2024-04-24 09:43:56 -04:00
existing_stripe_history = PaymentHistory . objects . filter ( user = self . user , payment_provider = " stripe " )
2022-06-05 12:19:49 -04:00
if existing_stripe_history . count ( ) :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BY~SN~FRDeleting~FW existing stripe history: ~SB %s payments "
% existing_stripe_history . count ( ) ,
)
2022-06-05 12:19:49 -04:00
existing_stripe_history . delete ( )
2024-04-24 09:43:56 -04:00
2012-12-03 14:35:21 -08:00
if self . stripe_id :
2018-05-01 14:18:59 -07:00
self . retrieve_stripe_ids ( )
2024-04-24 09:43:56 -04:00
2012-12-03 14:35:21 -08:00
stripe . api_key = settings . STRIPE_SECRET
2018-07-13 12:28:20 -04:00
seen_payments = set ( )
2018-05-01 14:18:59 -07:00
for stripe_id_model in self . user . stripe_ids . all ( ) :
stripe_id = stripe_id_model . stripe_id
stripe_customer = stripe . Customer . retrieve ( stripe_id )
2021-04-20 15:24:39 -04:00
stripe_payments = stripe . Charge . list ( customer = stripe_customer . id ) . data
2022-01-25 17:26:24 -05:00
stripe_subscriptions = stripe . Subscription . list ( customer = stripe_customer . id ) . data
2024-04-24 09:43:56 -04:00
2022-01-25 17:26:24 -05:00
for subscription in stripe_subscriptions :
2022-07-02 10:53:24 -04:00
if subscription . plan . active :
2022-01-25 17:26:24 -05:00
active_plan = subscription . plan . id
2022-02-16 09:20:43 -05:00
active_provider = " stripe "
2022-07-02 10:53:24 -04:00
if not subscription . cancel_at :
premium_renewal = True
2022-01-25 17:26:24 -05:00
break
2024-04-24 09:43:56 -04:00
2018-05-01 14:18:59 -07:00
for payment in stripe_payments :
created = datetime . datetime . fromtimestamp ( payment . created )
2024-04-24 09:43:56 -04:00
if payment . status == " failed " :
continue
if created in seen_payments :
continue
2018-07-13 12:28:20 -04:00
seen_payments . add ( created )
2018-05-01 14:29:13 -07:00
total_stripe_payments + = 1
2022-04-08 15:27:40 -04:00
refunded = None
if payment . refunded :
refunded = True
2024-04-24 09:43:56 -04:00
PaymentHistory . objects . get_or_create (
user = self . user ,
payment_date = created ,
payment_amount = payment . amount / 100.0 ,
payment_provider = " stripe " ,
refunded = refunded ,
)
2022-02-08 18:40:07 -05:00
else :
logging . user ( self . user , " ~FBNo Stripe payments " )
2013-12-20 12:45:28 -08:00
# Calculate payments in last year, then add together
2012-12-03 14:35:21 -08:00
payment_history = PaymentHistory . objects . filter ( user = self . user )
2013-12-20 12:45:28 -08:00
last_year = datetime . datetime . now ( ) - datetime . timedelta ( days = 364 )
recent_payments_count = 0
oldest_recent_payment_date = None
2015-06-30 16:05:58 -07:00
free_lifetime_premium = False
2012-12-03 14:35:21 -08:00
for payment in payment_history :
2021-01-03 17:48:08 -05:00
# Don't use free gift premiums in calculation for expiration
2015-06-30 16:05:58 -07:00
if payment . payment_amount == 0 :
2021-01-03 17:48:08 -05:00
logging . user ( self . user , " ~BY~SN~FWFree lifetime premium " )
2015-06-30 16:05:58 -07:00
free_lifetime_premium = True
2021-01-03 17:48:08 -05:00
continue
# Only update exiration if payment in the last year
2013-12-20 12:45:28 -08:00
if payment . payment_date > last_year :
recent_payments_count + = 1
2013-12-20 12:46:09 -08:00
if not oldest_recent_payment_date or payment . payment_date < oldest_recent_payment_date :
2013-12-20 12:45:28 -08:00
oldest_recent_payment_date = payment . payment_date
2024-04-24 09:43:56 -04:00
2021-01-03 17:48:08 -05:00
if oldest_recent_payment_date :
2024-04-24 09:43:56 -04:00
new_premium_expire = oldest_recent_payment_date + datetime . timedelta (
days = 365 * recent_payments_count
)
2015-05-18 14:13:48 -07:00
# Only move premium expire forward, never earlier. Also set expiration if not premium.
2024-04-24 09:43:56 -04:00
if (
force_expiration
or ( set_premium_expire and not self . premium_expire and not free_lifetime_premium )
or ( self . premium_expire and new_premium_expire > self . premium_expire )
) :
2015-05-18 14:13:48 -07:00
self . premium_expire = new_premium_expire
self . save ( )
2013-04-05 17:54:10 -07:00
2022-02-16 09:20:43 -05:00
if self . premium_renewal != premium_renewal or self . active_provider != active_provider :
2022-04-06 15:56:13 -04:00
active_sub_id = self . stripe_id
if active_provider == " paypal " :
active_sub_id = self . paypal_sub_id
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~FCTurning ~SB~ %s ~SN~FC premium renewal ( %s : %s ) "
% ( " FRoff " if not premium_renewal else " FBon " , active_provider , active_sub_id ) ,
)
2022-01-25 17:26:24 -05:00
self . premium_renewal = premium_renewal
2022-02-16 09:20:43 -05:00
self . active_provider = active_provider
2022-01-25 17:26:24 -05:00
self . save ( )
2014-11-17 13:54:39 -08:00
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BY~SN~FWFound ~SB~FB %s paypal~FW~SN and ~SB~FC %s stripe~FW~SN payments (~SB %s payments expire: ~SN~FB %s ~FW) "
% ( total_paypal_payments , total_stripe_payments , len ( payment_history ) , self . premium_expire ) ,
)
if set_premium_expire and not self . is_premium and self . premium_expire > datetime . datetime . now ( ) :
2015-01-05 16:06:48 -08:00
self . activate_premium ( )
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~FCActive plan: %s , stripe/paypal: %s / %s , is_archive? %s "
% (
active_plan ,
Profile . plan_to_stripe_price ( " archive " ) ,
Profile . plan_to_paypal_plan_id ( " archive " ) ,
self . is_archive ,
) ,
)
if active_plan == Profile . plan_to_stripe_price ( " pro " ) and not self . is_pro :
2022-01-25 17:26:24 -05:00
self . activate_pro ( )
2024-04-24 09:43:56 -04:00
elif active_plan == Profile . plan_to_stripe_price ( " archive " ) and not self . is_archive :
2022-01-25 17:26:24 -05:00
self . activate_archive ( )
2024-04-24 09:43:56 -04:00
elif active_plan == Profile . plan_to_paypal_plan_id ( " pro " ) and not self . is_pro :
2022-11-26 10:17:06 -05:00
self . activate_pro ( )
2024-04-24 09:43:56 -04:00
elif active_plan == Profile . plan_to_paypal_plan_id ( " archive " ) and not self . is_archive :
2022-02-08 12:49:40 -05:00
self . activate_archive ( )
2024-04-24 09:43:56 -04:00
2021-02-01 14:00:04 -05:00
def preference_value ( self , key , default = None ) :
preferences = json . decode ( self . preferences )
return preferences . get ( key , default )
2022-06-05 13:04:55 -04:00
@classmethod
def resync_stripe_and_paypal_history ( cls , start_days = 365 , end_days = 0 , skip = 0 ) :
start_date = datetime . datetime . now ( ) - datetime . timedelta ( days = start_days )
end_date = datetime . datetime . now ( ) - datetime . timedelta ( days = end_days )
2024-04-24 09:43:56 -04:00
payments = PaymentHistory . objects . filter ( payment_date__gte = start_date , payment_date__lte = end_date )
2022-06-05 13:04:55 -04:00
last_seen_date = None
for p , payment in enumerate ( payments ) :
if p < skip :
continue
if p == skip and skip > 0 :
print ( f " ---> Skipping { skip } payments... " )
if payment . payment_date . date ( ) != last_seen_date :
last_seen_date = payment . payment_date . date ( )
print ( f " ---> Payment date: { last_seen_date } (# { p } ) " )
2024-04-24 09:43:56 -04:00
2022-06-05 13:04:55 -04:00
payment . user . profile . setup_premium_history ( )
2019-07-16 12:00:10 -07:00
@classmethod
2019-07-16 12:02:50 -07:00
def reimport_stripe_history ( cls , limit = 10 , days = 7 , starting_after = None ) :
2019-07-16 12:00:10 -07:00
stripe . api_key = settings . STRIPE_SECRET
2024-04-24 09:43:56 -04:00
week = ( datetime . datetime . now ( ) - datetime . timedelta ( days = days ) ) . strftime ( " %s " )
2019-07-16 12:00:10 -07:00
failed = [ ]
i = 0
2024-04-24 09:43:56 -04:00
2019-07-16 12:00:10 -07:00
while True :
logging . debug ( " ---> At %s / %s " % ( i , starting_after ) )
i + = 1
try :
2024-04-24 09:43:56 -04:00
data = stripe . Charge . list ( created = { " gt " : week } , count = limit , starting_after = starting_after )
2021-04-29 15:25:02 -04:00
except stripe . error . APIConnectionError :
2019-07-16 12:00:10 -07:00
time . sleep ( 10 )
continue
2024-04-24 09:43:56 -04:00
charges = data [ " data " ]
2019-07-16 12:00:10 -07:00
if not len ( charges ) :
logging . debug ( " At %s ( %s ), finished " % ( i , starting_after ) )
break
starting_after = charges [ - 1 ] [ " id " ]
2024-04-24 09:43:56 -04:00
customers = [ c [ " customer " ] for c in charges if " customer " in c ]
2019-07-16 12:00:10 -07:00
for customer in customers :
if not customer :
2020-06-17 00:17:32 -04:00
print ( " ***> No customer! " )
2019-07-16 12:00:10 -07:00
continue
try :
profile = Profile . objects . get ( stripe_id = customer )
user = profile . user
except Profile . DoesNotExist :
logging . debug ( " ***> Couldn ' t find stripe_id= %s " % customer )
failed . append ( customer )
continue
except Profile . MultipleObjectsReturned :
logging . debug ( " ***> Multiple stripe_id= %s " % customer )
failed . append ( customer )
continue
try :
user . profile . setup_premium_history ( )
2021-04-29 15:25:02 -04:00
except stripe . error . APIConnectionError :
2019-07-16 12:00:10 -07:00
logging . debug ( " ***> Failed: %s " % user . username )
failed . append ( user . username )
time . sleep ( 2 )
continue
2024-04-24 09:43:56 -04:00
return " , " . join ( failed )
2022-02-10 13:40:07 -05:00
def refund_premium ( self , partial = False , provider = None ) :
2013-05-10 12:05:24 -07:00
refunded = False
2022-02-10 13:40:07 -05:00
if provider == " paypal " :
2022-04-08 15:07:58 -04:00
refunded = self . refund_paypal_payment_from_subscription ( self . paypal_sub_id , prorate = partial )
self . cancel_premium_paypal ( )
2022-02-10 13:40:07 -05:00
elif provider == " stripe " :
refunded = self . refund_latest_stripe_payment ( partial = partial )
2022-04-08 15:07:58 -04:00
# self.cancel_premium_stripe()
2022-02-10 13:40:07 -05:00
else :
# Find last payment, refund that
2024-04-24 09:43:56 -04:00
payment_history = PaymentHistory . objects . filter (
user = self . user , payment_provider__in = [ " paypal " , " stripe " ]
)
2022-02-10 13:40:07 -05:00
if payment_history . count ( ) :
provider = payment_history [ 0 ] . payment_provider
if provider == " stripe " :
refunded = self . refund_latest_stripe_payment ( partial = partial )
2022-04-08 15:07:58 -04:00
# self.cancel_premium_stripe()
2022-02-10 13:40:07 -05:00
elif provider == " paypal " :
2024-04-24 09:43:56 -04:00
refunded = self . refund_paypal_payment_from_subscription (
self . paypal_sub_id , prorate = partial
)
2022-04-08 15:07:58 -04:00
self . cancel_premium_paypal ( )
2022-02-10 13:40:07 -05:00
return refunded
2024-04-24 09:43:56 -04:00
2022-02-10 13:40:07 -05:00
def refund_latest_stripe_payment ( self , partial = False ) :
refunded = False
if not self . stripe_id :
return
2024-04-24 09:43:56 -04:00
2022-02-10 13:40:07 -05:00
stripe . api_key = settings . STRIPE_SECRET
stripe_customer = stripe . Customer . retrieve ( self . stripe_id )
stripe_payments = stripe . Charge . list ( customer = stripe_customer . id ) . data
if partial :
stripe_payments [ 0 ] . refund ( amount = 1200 )
refunded = 12
2013-05-23 16:28:39 -07:00
else :
2022-02-10 13:40:07 -05:00
stripe_payments [ 0 ] . refund ( )
self . cancel_premium_stripe ( )
2024-04-24 09:43:56 -04:00
refunded = stripe_payments [ 0 ] . amount / 100
2022-02-10 13:40:07 -05:00
logging . user ( self . user , " ~FRRefunding stripe payment: $ %s " % refunded )
return refunded
2024-04-24 09:43:56 -04:00
2022-04-08 15:07:58 -04:00
def refund_paypal_payment_from_subscription ( self , paypal_sub_id , prorate = False ) :
2024-04-24 09:43:56 -04:00
if not paypal_sub_id :
2022-02-10 13:40:07 -05:00
return
2024-04-24 09:43:56 -04:00
2022-02-10 13:40:07 -05:00
paypal_api = self . paypal_api ( )
refunded = False
2014-09-24 17:00:09 -07:00
2022-02-10 13:40:07 -05:00
# Find transaction from subscription
2022-04-08 15:07:58 -04:00
now = datetime . datetime . now ( ) + datetime . timedelta ( days = 1 )
2022-02-10 13:40:07 -05:00
# 200 days captures Paypal's 180 day limit on refunds
2024-04-24 09:43:56 -04:00
start_date = ( now - datetime . timedelta ( days = 200 ) ) . strftime ( " % Y- % m- %d T % H: % M: % SZ " )
2022-02-10 13:40:07 -05:00
end_date = now . strftime ( " % Y- % m- %d T % H: % M: % SZ " )
try :
2024-04-24 09:43:56 -04:00
transactions = paypal_api . get (
f " /v1/billing/subscriptions/ { paypal_sub_id } /transactions?start_time= { start_date } &end_time= { end_date } "
)
2022-02-10 13:40:07 -05:00
except paypalrestsdk . ResourceNotFound :
transactions = { }
2024-04-24 09:43:56 -04:00
if " transactions " not in transactions or not len ( transactions [ " transactions " ] ) :
logging . user (
self . user , f " ~FRCouldn ' t find paypal transactions for refund: { paypal_sub_id } { transactions } "
)
2022-02-10 13:40:07 -05:00
return
2024-04-24 09:43:56 -04:00
2022-02-10 13:40:07 -05:00
# Refund the latest transaction
2024-04-24 09:43:56 -04:00
transaction = transactions [ " transactions " ] [ 0 ]
today = datetime . datetime . now ( ) . strftime ( " % B %d , % Y " )
2022-02-10 13:40:07 -05:00
url = f " /v2/payments/captures/ { transaction [ ' id ' ] } /refund "
2024-04-24 09:43:56 -04:00
refund_amount = float ( transaction [ " amount_with_breakdown " ] [ " gross_amount " ] [ " value " ] )
2022-04-08 15:07:58 -04:00
if prorate :
2024-04-24 09:43:56 -04:00
transaction_date = dateutil . parser . parse ( transaction [ " time " ] )
2022-04-08 15:07:58 -04:00
days_since = ( datetime . datetime . now ( ) - transaction_date . replace ( tzinfo = None ) ) . days
if days_since < 365 :
2024-04-24 09:43:56 -04:00
days_left = 365 - days_since
pct_left = days_left / 365
2022-04-08 15:27:40 -04:00
refund_amount = pct_left * refund_amount
2022-04-08 15:07:58 -04:00
else :
logging . user ( self . user , f " ~FRCouldn ' t prorate paypal payment, too old: ~SB { transaction } " )
2022-02-10 13:40:07 -05:00
try :
2024-04-24 09:43:56 -04:00
response = paypal_api . post (
url ,
{
" reason " : f " Refunded on { today } " ,
" amount " : {
" currency_code " : " USD " ,
" value " : f " { refund_amount : .2f } " ,
} ,
} ,
)
2022-02-10 13:40:07 -05:00
except paypalrestsdk . exceptions . ResourceInvalid as e :
response = e . response . json ( )
2024-04-24 09:43:56 -04:00
if len ( response . get ( " details " , [ ] ) ) :
response = response [ " details " ] [ 0 ] [ " description " ]
2022-04-08 15:07:58 -04:00
if settings . DEBUG :
logging . user ( self . user , f " Paypal refund response: { response } " )
2024-04-24 09:43:56 -04:00
if " status " in response and response [ " status " ] == " COMPLETED " :
refunded = int ( float ( transaction [ " amount_with_breakdown " ] [ " gross_amount " ] [ " value " ] ) )
2022-04-08 15:27:40 -04:00
logging . user ( self . user , " ~FRRefunding paypal payment: $ %s / %s " % ( refund_amount , refunded ) )
2022-02-10 13:40:07 -05:00
else :
logging . user ( self . user , " ~FRCouldn ' t refund paypal payment: %s " % response )
refunded = response
2024-04-24 09:43:56 -04:00
2013-05-10 12:05:24 -07:00
return refunded
2024-04-24 09:43:56 -04:00
2013-03-13 15:46:51 -07:00
def cancel_premium ( self ) :
2013-05-23 16:28:39 -07:00
paypal_cancel = self . cancel_premium_paypal ( )
stripe_cancel = self . cancel_premium_stripe ( )
2024-04-24 09:43:56 -04:00
self . setup_premium_history ( ) # Sure, webhooks will force new history, but they take forever
2017-03-30 11:12:21 -07:00
return stripe_cancel or paypal_cancel
2024-04-24 09:43:56 -04:00
2022-04-08 15:07:58 -04:00
def cancel_premium_paypal ( self , cancel_older_subscriptions_only = False ) :
2022-02-09 12:26:35 -05:00
self . retrieve_paypal_ids ( )
if not self . paypal_sub_id :
logging . user ( self . user , " ~FRUser doesn ' t have a Paypal subscription, how did we get here? " )
2013-05-23 16:28:39 -07:00
return
2022-04-08 15:07:58 -04:00
if not self . premium_renewal and not cancel_older_subscriptions_only :
2024-04-24 09:43:56 -04:00
logging . user (
self . user , " ~FRUser ~SBalready~SN canceled Paypal subscription: %s " % self . paypal_sub_id
)
2022-02-09 12:26:35 -05:00
return
paypal_api = self . paypal_api ( )
2024-04-24 09:43:56 -04:00
today = datetime . datetime . now ( ) . strftime ( " % B %d , % Y " )
2022-02-09 12:26:35 -05:00
for paypal_id_model in self . user . paypal_ids . all ( ) :
paypal_id = paypal_id_model . paypal_sub_id
2022-04-08 15:07:58 -04:00
if cancel_older_subscriptions_only and paypal_id == self . paypal_sub_id :
2024-04-24 09:43:56 -04:00
logging . user (
self . user , " ~FBNot canceling active Paypal subscription: %s " % self . paypal_sub_id
)
2022-04-08 15:07:58 -04:00
continue
2022-02-09 12:26:35 -05:00
try :
2024-04-24 09:43:56 -04:00
paypal_subscription = paypal_api . get ( f " /v1/billing/subscriptions/ { paypal_id } " )
2022-02-09 12:26:35 -05:00
except paypalrestsdk . ResourceNotFound :
logging . user ( self . user , f " ~FRCouldn ' t find paypal payments: { paypal_id } " )
continue
2024-04-24 09:43:56 -04:00
if paypal_subscription [ " status " ] not in [ " ACTIVE " , " APPROVED " , " APPROVAL_PENDING " ] :
2022-02-09 12:26:35 -05:00
logging . user ( self . user , " ~FRUser ~SBalready~SN canceled Paypal subscription: %s " % paypal_id )
continue
url = f " /v1/billing/subscriptions/ { paypal_id } /suspend "
2022-07-01 12:35:59 -04:00
try :
2024-04-24 09:43:56 -04:00
response = paypal_api . post ( url , { " reason " : f " Cancelled on { today } " } )
2022-07-01 12:35:59 -04:00
except paypalrestsdk . ResourceNotFound as e :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
f " ~FRCouldn ' t find paypal response during ~FB~SB { paypal_id } ~SN~FR profile suspend: ~SB~FB { e } " ,
)
2022-02-09 12:26:35 -05:00
logging . user ( self . user , " ~FRCanceling Paypal subscription: %s " % paypal_id )
2022-04-08 15:07:58 -04:00
return paypal_id
2022-02-09 12:26:35 -05:00
2013-05-23 16:28:39 -07:00
return True
2024-04-24 09:43:56 -04:00
2013-03-13 15:46:51 -07:00
def cancel_premium_stripe ( self ) :
if not self . stripe_id :
return
2024-04-24 09:43:56 -04:00
2013-03-13 15:46:51 -07:00
stripe . api_key = settings . STRIPE_SECRET
2022-02-16 13:27:56 -05:00
for stripe_id_model in self . user . stripe_ids . all ( ) :
stripe_id = stripe_id_model . stripe_id
stripe_customer = stripe . Customer . retrieve ( stripe_id )
try :
subscriptions = stripe . Subscription . list ( customer = stripe_customer )
for subscription in subscriptions . data :
2024-04-24 09:43:56 -04:00
stripe . Subscription . modify ( subscription [ " id " ] , cancel_at_period_end = True )
logging . user ( self . user , " ~FRCanceling Stripe subscription: %s " % subscription [ " id " ] )
2022-02-16 13:27:56 -05:00
except stripe . error . InvalidRequestError :
logging . user ( self . user , " ~FRFailed to cancel Stripe subscription: %s " % stripe_id )
continue
2024-04-24 09:43:56 -04:00
2013-03-13 15:46:51 -07:00
return True
2024-04-24 09:43:56 -04:00
2018-04-27 10:26:56 -07:00
def retrieve_stripe_ids ( self ) :
if not self . stripe_id :
return
2024-04-24 09:43:56 -04:00
2018-05-01 14:26:55 -07:00
stripe . api_key = settings . STRIPE_SECRET
2018-04-27 10:26:56 -07:00
stripe_customer = stripe . Customer . retrieve ( self . stripe_id )
stripe_email = stripe_customer . email
2024-04-24 09:43:56 -04:00
2018-05-01 14:18:59 -07:00
stripe_ids = set ( )
2018-04-27 10:26:56 -07:00
for email in set ( [ stripe_email , self . user . email ] ) :
customers = stripe . Customer . list ( email = email )
2018-05-01 14:18:59 -07:00
for customer in customers :
stripe_ids . add ( customer . stripe_id )
2024-04-24 09:43:56 -04:00
2018-05-01 14:18:59 -07:00
self . user . stripe_ids . all ( ) . delete ( )
for stripe_id in stripe_ids :
self . user . stripe_ids . create ( stripe_id = stripe_id )
2024-04-24 09:43:56 -04:00
2022-06-05 09:46:27 -04:00
def retrieve_paypal_ids ( self , force = False ) :
if self . paypal_sub_id and not force :
2022-02-08 12:49:40 -05:00
return
2024-04-24 09:43:56 -04:00
ipns = PayPalIPN . objects . filter (
Q ( custom = self . user . username ) | Q ( payer_email = self . user . email ) | Q ( custom = self . user . pk )
) . order_by ( " -payment_date " )
2022-02-08 18:40:07 -05:00
if not len ( ipns ) :
2022-02-08 12:49:40 -05:00
return
2024-04-24 09:43:56 -04:00
2022-02-08 18:40:07 -05:00
self . paypal_sub_id = ipns [ 0 ] . subscr_id
self . save ( )
2022-02-08 12:49:40 -05:00
2022-02-08 18:40:07 -05:00
paypal_ids = set ( )
for ipn in ipns :
2024-04-24 09:43:56 -04:00
if not ipn . subscr_id :
continue
2022-02-08 18:40:07 -05:00
paypal_ids . add ( ipn . subscr_id )
2024-04-24 09:43:56 -04:00
2022-02-08 18:40:07 -05:00
seen_paypal_ids = set ( p . paypal_sub_id for p in self . user . paypal_ids . all ( ) )
for paypal_id in paypal_ids :
if paypal_id in seen_paypal_ids :
continue
self . user . paypal_ids . create ( paypal_sub_id = paypal_id )
2024-04-24 09:43:56 -04:00
2017-03-30 11:12:21 -07:00
@property
def latest_paypal_email ( self ) :
ipn = PayPalIPN . objects . filter ( custom = self . user . username )
2021-01-23 18:01:19 -05:00
if not len ( ipn ) :
ipn = PayPalIPN . objects . filter ( payer_email = self . user . email )
2017-03-30 11:12:21 -07:00
if not len ( ipn ) :
return
2024-04-24 09:43:56 -04:00
2017-03-30 11:12:21 -07:00
return ipn [ 0 ] . payer_email
2024-04-24 09:43:56 -04:00
2021-03-22 10:25:14 -04:00
def update_email ( self , new_email ) :
from apps . social . models import MSocialProfile
if self . user . email == new_email :
return
self . user . email = new_email
self . user . save ( )
2024-04-24 09:43:56 -04:00
2021-03-22 10:25:14 -04:00
sp = MSocialProfile . get_user ( self . user . pk )
sp . email = new_email
sp . save ( )
if self . stripe_id :
stripe_customer = self . stripe_customer ( )
2024-04-24 09:43:56 -04:00
stripe_customer . update ( { " email " : new_email } )
2021-03-22 10:25:14 -04:00
stripe_customer . save ( )
def stripe_customer ( self ) :
if self . stripe_id :
stripe . api_key = settings . STRIPE_SECRET
stripe_customer = stripe . Customer . retrieve ( self . stripe_id )
return stripe_customer
2024-04-24 09:43:56 -04:00
2022-02-09 12:26:35 -05:00
def paypal_api ( self ) :
if self . paypal_sub_id :
2024-04-24 09:43:56 -04:00
api = paypalrestsdk . Api (
{
" mode " : " sandbox " if settings . DEBUG else " live " ,
" client_id " : settings . PAYPAL_API_CLIENTID ,
" client_secret " : settings . PAYPAL_API_SECRET ,
}
)
2022-02-09 12:26:35 -05:00
return api
2024-04-24 09:43:56 -04:00
2020-08-25 21:08:27 -04:00
def activate_ios_premium ( self , transaction_identifier = None , amount = 36 ) :
2024-04-24 09:43:56 -04:00
payments = PaymentHistory . objects . filter (
user = self . user ,
payment_identifier = transaction_identifier ,
payment_date__gte = datetime . datetime . now ( ) - datetime . timedelta ( days = 3 ) ,
)
2017-11-15 17:26:27 -08:00
if len ( payments ) :
# Already paid
2024-04-24 09:43:56 -04:00
logging . user (
self . user , " ~FG~BBAlready paid iOS premium subscription: $ %s ~FW " % transaction_identifier
)
2017-11-15 17:26:27 -08:00
return False
2024-04-24 09:43:56 -04:00
PaymentHistory . objects . create (
user = self . user ,
payment_date = datetime . datetime . now ( ) ,
payment_amount = amount ,
payment_provider = " ios-subscription " ,
payment_identifier = transaction_identifier ,
)
2019-09-09 21:17:10 -04:00
self . setup_premium_history ( )
2024-04-24 09:43:56 -04:00
2017-11-15 17:26:27 -08:00
if not self . is_premium :
self . activate_premium ( )
2024-04-24 09:43:56 -04:00
2020-08-25 21:08:27 -04:00
logging . user ( self . user , " ~FG~BBNew iOS premium subscription: $ %s ~FW " % amount )
return True
2024-04-24 09:43:56 -04:00
2020-08-25 21:08:27 -04:00
def activate_android_premium ( self , order_id = None , amount = 36 ) :
2024-04-24 09:43:56 -04:00
payments = PaymentHistory . objects . filter (
user = self . user ,
payment_identifier = order_id ,
payment_date__gte = datetime . datetime . now ( ) - datetime . timedelta ( days = 3 ) ,
)
2020-08-25 21:08:27 -04:00
if len ( payments ) :
# Already paid
logging . user ( self . user , " ~FG~BBAlready paid Android premium subscription: $ %s ~FW " % amount )
return False
2024-04-24 09:43:56 -04:00
PaymentHistory . objects . create (
user = self . user ,
payment_date = datetime . datetime . now ( ) ,
payment_amount = amount ,
payment_provider = " android-subscription " ,
payment_identifier = order_id ,
)
2020-08-25 21:08:27 -04:00
self . setup_premium_history ( )
2024-04-24 09:43:56 -04:00
2022-10-25 09:48:58 -04:00
if order_id == " nb.premium.archive.99 " :
self . activate_archive ( )
elif not self . is_premium :
2020-08-25 21:08:27 -04:00
self . activate_premium ( )
2024-04-24 09:43:56 -04:00
2020-08-25 21:08:27 -04:00
logging . user ( self . user , " ~FG~BBNew Android premium subscription: $ %s ~FW " % amount )
2017-11-15 17:26:27 -08:00
return True
2024-04-24 09:43:56 -04:00
2015-07-30 18:10:55 -07:00
@classmethod
2015-08-03 12:23:49 -07:00
def clear_dead_spammers ( self , days = 30 , confirm = False ) :
2024-04-24 09:43:56 -04:00
users = User . objects . filter (
date_joined__gte = datetime . datetime . now ( ) - datetime . timedelta ( days = days )
) . order_by ( " -date_joined " )
2015-07-30 18:10:55 -07:00
usernames = set ( )
2024-04-24 09:43:56 -04:00
numerics = re . compile ( r " [0-9]+ " )
2015-07-30 18:10:55 -07:00
for user in users :
2024-04-24 09:43:56 -04:00
opens = UserSubscription . objects . filter ( user = user ) . aggregate ( sum = Sum ( " feed_opens " ) ) [ " sum " ]
2015-11-23 11:26:22 -08:00
reads = RUserStory . read_story_count ( user . pk )
has_numbers = numerics . search ( user . username )
2018-01-18 16:10:41 -08:00
try :
has_profile = user . profile . last_seen_ip
except Profile . DoesNotExist :
usernames . add ( user . username )
2024-04-24 09:43:56 -04:00
print (
" ---> Missing profile: %-20s %-30s %-6s %-6s " % ( user . username , user . email , opens , reads )
)
2018-01-18 16:10:41 -08:00
continue
2015-11-23 11:26:22 -08:00
if opens is None and not reads and has_numbers :
usernames . add ( user . username )
2020-06-17 00:17:32 -04:00
print ( " ---> Numerics: %-20s %-30s %-6s %-6s " % ( user . username , user . email , opens , reads ) )
2018-01-18 16:10:41 -08:00
elif not has_profile :
2015-11-23 11:26:22 -08:00
usernames . add ( user . username )
2020-06-17 00:17:32 -04:00
print ( " ---> No IP: %-20s %-30s %-6s %-6s " % ( user . username , user . email , opens , reads ) )
2024-04-24 09:43:56 -04:00
if not confirm :
return usernames
2015-07-30 18:10:55 -07:00
for username in usernames :
2019-10-03 09:05:28 -04:00
try :
u = User . objects . get ( username = username )
except User . DoesNotExist :
continue
2015-07-30 18:10:55 -07:00
u . profile . delete_user ( confirm = True )
RNewUserQueue . user_count ( )
RNewUserQueue . activate_all ( )
2024-04-24 09:43:56 -04:00
2015-07-28 18:46:37 -07:00
@classmethod
2015-08-05 13:59:26 -07:00
def count_feed_subscribers ( self , feed_id = None , user_id = None , verbose = True ) :
2015-07-28 18:46:37 -07:00
SUBSCRIBER_EXPIRE = datetime . datetime . now ( ) - datetime . timedelta ( days = settings . SUBSCRIBER_EXPIRE )
r = redis . Redis ( connection_pool = settings . REDIS_FEED_SUB_POOL )
entire_feed_counted = False
2024-04-24 09:43:56 -04:00
2015-07-29 11:57:11 -07:00
if verbose :
2015-08-24 14:26:49 -07:00
feed = Feed . get_by_id ( feed_id )
2024-04-24 09:43:56 -04:00
logging . debug (
" ---> [ %-30s ] ~SN~FBCounting subscribers for feed:~SB~FM %s ~SN~FB user:~SB~FM %s "
% ( feed . log_title [ : 30 ] , feed_id , user_id )
)
2015-07-28 18:46:37 -07:00
if feed_id :
feed_ids = [ feed_id ]
elif user_id :
2024-04-24 09:43:56 -04:00
feed_ids = [
us [ " feed_id " ]
for us in UserSubscription . objects . filter ( user = user_id , active = True ) . values ( " feed_id " )
]
2015-07-28 18:46:37 -07:00
else :
assert False , " feed_id or user_id required "
2011-01-30 23:56:51 -05:00
2015-07-28 18:46:37 -07:00
if feed_id and not user_id :
entire_feed_counted = True
2024-04-24 09:43:56 -04:00
2015-07-28 18:46:37 -07:00
for feed_id in feed_ids :
total = 0
premium = 0
active = 0
active_premium = 0
2022-01-11 10:59:45 -05:00
archive = 0
2022-01-10 17:00:27 -05:00
pro = 0
2024-04-24 09:43:56 -04:00
key = " s: %s " % feed_id
premium_key = " sp: %s " % feed_id
archive_key = " sarchive: %s " % feed_id
pro_key = " spro: %s " % feed_id
2015-07-28 18:46:37 -07:00
if user_id :
2024-04-24 09:43:56 -04:00
active = UserSubscription . objects . get ( feed_id = feed_id , user_id = user_id ) . only ( " active " ) . active
2022-01-11 15:56:19 -05:00
user_active_feeds = dict ( [ ( user_id , active ) ] )
2015-07-28 18:46:37 -07:00
else :
2024-04-24 09:43:56 -04:00
user_active_feeds = dict (
[
( us . user_id , us . active )
for us in UserSubscription . objects . filter ( feed_id = feed_id ) . only ( " user " , " active " )
]
)
profiles = Profile . objects . filter ( user_id__in = list ( user_active_feeds . keys ( ) ) ) . values (
" user_id " , " last_seen_on " , " is_premium " , " is_archive " , " is_pro "
)
2015-07-28 18:46:37 -07:00
feed = Feed . get_by_id ( feed_id )
2024-04-24 09:43:56 -04:00
2015-07-28 20:46:30 -07:00
if entire_feed_counted :
2022-01-11 15:56:19 -05:00
pipeline = r . pipeline ( )
pipeline . delete ( key )
pipeline . delete ( premium_key )
pipeline . delete ( archive_key )
pipeline . delete ( pro_key )
pipeline . execute ( )
2024-04-24 09:43:56 -04:00
2015-07-28 18:46:37 -07:00
for profiles_group in chunks ( profiles , 20 ) :
pipeline = r . pipeline ( )
for profile in profiles_group :
2024-04-24 09:43:56 -04:00
last_seen_on = int ( profile [ " last_seen_on " ] . strftime ( " %s " ) )
muted_feed = not bool ( user_active_feeds [ profile [ " user_id " ] ] )
2015-07-28 20:46:30 -07:00
if muted_feed :
last_seen_on = 0
2024-04-24 09:43:56 -04:00
pipeline . zadd ( key , { profile [ " user_id " ] : last_seen_on } )
2015-07-28 18:46:37 -07:00
total + = 1
2024-04-24 09:43:56 -04:00
if profile [ " is_premium " ] :
pipeline . zadd ( premium_key , { profile [ " user_id " ] : last_seen_on } )
2015-07-28 18:46:37 -07:00
premium + = 1
2015-07-28 19:04:06 -07:00
else :
2024-04-24 09:43:56 -04:00
pipeline . zrem ( premium_key , profile [ " user_id " ] )
if profile [ " is_archive " ] :
pipeline . zadd ( archive_key , { profile [ " user_id " ] : last_seen_on } )
2022-01-11 10:59:45 -05:00
archive + = 1
else :
2024-04-24 09:43:56 -04:00
pipeline . zrem ( archive_key , profile [ " user_id " ] )
if profile [ " is_pro " ] :
pipeline . zadd ( pro_key , { profile [ " user_id " ] : last_seen_on } )
2022-01-10 17:00:27 -05:00
pro + = 1
else :
2024-04-24 09:43:56 -04:00
pipeline . zrem ( pro_key , profile [ " user_id " ] )
if profile [ " last_seen_on " ] > SUBSCRIBER_EXPIRE and not muted_feed :
2015-07-28 18:46:37 -07:00
active + = 1
2024-04-24 09:43:56 -04:00
if profile [ " is_premium " ] :
2015-07-28 18:46:37 -07:00
active_premium + = 1
2024-04-24 09:43:56 -04:00
2015-07-28 18:46:37 -07:00
pipeline . execute ( )
2024-04-24 09:43:56 -04:00
2015-07-28 18:46:37 -07:00
if entire_feed_counted :
2024-04-24 09:43:56 -04:00
now = int ( datetime . datetime . now ( ) . strftime ( " %s " ) )
r . zadd ( key , { - 1 : now } )
r . expire ( key , settings . SUBSCRIBER_EXPIRE * 24 * 60 * 60 )
2020-06-29 17:39:55 -04:00
r . zadd ( premium_key , { - 1 : now } )
2024-04-24 09:43:56 -04:00
r . expire ( premium_key , settings . SUBSCRIBER_EXPIRE * 24 * 60 * 60 )
2022-01-11 15:56:19 -05:00
r . zadd ( archive_key , { - 1 : now } )
2024-04-24 09:43:56 -04:00
r . expire ( archive_key , settings . SUBSCRIBER_EXPIRE * 24 * 60 * 60 )
2022-01-11 15:56:19 -05:00
r . zadd ( pro_key , { - 1 : now } )
2024-04-24 09:43:56 -04:00
r . expire ( pro_key , settings . SUBSCRIBER_EXPIRE * 24 * 60 * 60 )
logging . info (
" ---> [ %-30s ] ~SN~FBCounting subscribers, storing in ~SBredis~SN: ~FMt:~SB~FM %s ~SN a:~SB %s ~SN p:~SB %s ~SN ap:~SB %s ~SN archive:~SB %s ~SN pro:~SB %s "
% ( feed . log_title [ : 30 ] , total , active , premium , active_premium , archive , pro )
)
2015-07-28 19:04:06 -07:00
@classmethod
2015-07-28 19:10:19 -07:00
def count_all_feed_subscribers_for_user ( self , user ) :
2015-07-28 19:04:06 -07:00
r = redis . Redis ( connection_pool = settings . REDIS_FEED_SUB_POOL )
if not isinstance ( user , User ) :
user = User . objects . get ( pk = user )
2024-04-24 09:43:56 -04:00
active_feed_ids = [
us [ " feed_id " ]
for us in UserSubscription . objects . filter ( user = user . pk , active = True ) . values ( " feed_id " )
]
muted_feed_ids = [
us [ " feed_id " ]
for us in UserSubscription . objects . filter ( user = user . pk , active = False ) . values ( " feed_id " )
]
logging . user (
user ,
" ~SN~FBRefreshing user last_login_on for ~SB %s ~SN/~SB %s subscriptions~SN "
% ( len ( active_feed_ids ) , len ( muted_feed_ids ) ) ,
)
2015-07-28 20:46:30 -07:00
for feed_ids in [ active_feed_ids , muted_feed_ids ] :
for feeds_group in chunks ( feed_ids , 20 ) :
pipeline = r . pipeline ( )
for feed_id in feeds_group :
2024-04-24 09:43:56 -04:00
key = " s: %s " % feed_id
premium_key = " sp: %s " % feed_id
archive_key = " sarchive: %s " % feed_id
pro_key = " spro: %s " % feed_id
2015-07-28 19:04:06 -07:00
2024-04-24 09:43:56 -04:00
last_seen_on = int ( user . profile . last_seen_on . strftime ( " %s " ) )
2015-07-28 20:46:30 -07:00
if feed_ids is muted_feed_ids :
last_seen_on = 0
2024-04-24 09:43:56 -04:00
pipeline . zadd ( key , { user . pk : last_seen_on } )
2015-07-28 20:46:30 -07:00
if user . profile . is_premium :
2024-04-24 09:43:56 -04:00
pipeline . zadd ( premium_key , { user . pk : last_seen_on } )
2015-07-28 20:46:30 -07:00
else :
pipeline . zrem ( premium_key , user . pk )
2022-01-11 10:59:45 -05:00
if user . profile . is_archive :
2024-04-24 09:43:56 -04:00
pipeline . zadd ( archive_key , { user . pk : last_seen_on } )
2022-01-11 10:59:45 -05:00
else :
pipeline . zrem ( archive_key , user . pk )
2022-01-10 17:00:27 -05:00
if user . profile . is_pro :
2024-04-24 09:43:56 -04:00
pipeline . zadd ( pro_key , { user . pk : last_seen_on } )
2022-01-10 17:00:27 -05:00
else :
pipeline . zrem ( pro_key , user . pk )
2015-07-28 20:46:30 -07:00
pipeline . execute ( )
2024-04-24 09:43:56 -04:00
2011-09-21 17:49:26 -07:00
def send_new_user_email ( self ) :
if not self . user . email or not self . send_emails :
2011-09-19 08:56:16 -07:00
return
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_new_account.txt " , locals ( ) )
html = render_to_string ( " mail/email_new_account.xhtml " , locals ( ) )
2011-09-19 08:56:16 -07:00
subject = " Welcome to NewsBlur, %s " % ( self . user . username )
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2011-09-19 08:56:16 -07:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
2011-09-23 18:13:16 -07:00
logging . user ( self . user , " ~BB~FM~SBSending email for new user: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
2014-10-14 15:59:46 -07:00
def send_opml_export_email ( self , reason = None , force = False ) :
2013-05-23 18:14:21 -07:00
if not self . user . email :
return
2024-04-24 09:43:56 -04:00
emails_sent = MSentEmail . objects . filter ( receiver_user_id = self . user . pk , email_type = " opml_export " )
2014-10-14 15:59:46 -07:00
day_ago = datetime . datetime . now ( ) - datetime . timedelta ( days = 1 )
for email in emails_sent :
if email . date_sent > day_ago and not force :
logging . user ( self . user , " ~SN~FMNot sending opml export email, already sent today. " )
return
2024-04-24 09:43:56 -04:00
MSentEmail . record ( receiver_user_id = self . user . pk , email_type = " opml_export " )
2013-05-23 18:14:21 -07:00
exporter = OPMLExporter ( self . user )
2024-04-24 09:43:56 -04:00
opml = exporter . process ( )
2013-04-22 15:24:38 -07:00
2013-05-23 18:14:21 -07:00
params = {
2024-04-24 09:43:56 -04:00
" feed_count " : UserSubscription . objects . filter ( user = self . user ) . count ( ) ,
" reason " : reason ,
2013-05-23 18:14:21 -07:00
}
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_opml_export.txt " , params )
html = render_to_string ( " mail/email_opml_export.xhtml " , params )
2013-05-23 18:14:21 -07:00
subject = " Backup OPML file of your NewsBlur sites "
2024-04-24 09:43:56 -04:00
filename = " NewsBlur Subscriptions - %s .xml " % datetime . datetime . now ( ) . strftime ( " % Y- % m- %d " )
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2013-05-23 18:14:21 -07:00
msg . attach_alternative ( html , " text/html " )
2024-04-24 09:43:56 -04:00
msg . attach ( filename , opml , " text/xml " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
2022-03-14 11:06:01 -04:00
from apps . social . models import MActivity
2024-04-24 09:43:56 -04:00
2022-03-14 15:52:22 -04:00
MActivity . new_opml_export ( user_id = self . user . pk , count = exporter . feed_count , automated = True )
2024-04-24 09:43:56 -04:00
2013-05-23 18:14:21 -07:00
logging . user ( self . user , " ~BB~FM~SBSending OPML backup email to: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
2013-04-22 15:24:38 -07:00
def send_first_share_to_blurblog_email ( self , force = False ) :
2024-04-24 09:50:42 -04:00
from apps . social . models import MSharedStory , MSocialProfile
2024-04-24 09:43:56 -04:00
2013-04-22 15:24:38 -07:00
if not self . user . email :
return
2024-04-24 09:43:56 -04:00
params = dict ( receiver_user_id = self . user . pk , email_type = " first_share " )
2015-07-20 16:44:50 -07:00
try :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . get ( * * params )
2015-07-20 16:44:50 -07:00
if not force :
# Return if email already sent
return
except MSentEmail . DoesNotExist :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . create ( * * params )
2024-04-24 09:43:56 -04:00
2013-04-22 15:24:38 -07:00
social_profile = MSocialProfile . objects . get ( user_id = self . user . pk )
params = {
2024-04-24 09:43:56 -04:00
" shared_stories " : MSharedStory . objects . filter ( user_id = self . user . pk ) . count ( ) ,
" blurblog_url " : social_profile . blurblog_url ,
" blurblog_rss " : social_profile . blurblog_rss ,
2013-04-22 15:24:38 -07:00
}
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_first_share_to_blurblog.txt " , params )
html = render_to_string ( " mail/email_first_share_to_blurblog.xhtml " , params )
2013-04-22 15:24:38 -07:00
subject = " Your shared stories on NewsBlur are available on your Blurblog "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2013-04-22 15:24:38 -07:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
2013-04-22 15:24:38 -07:00
logging . user ( self . user , " ~BB~FM~SBSending first share to blurblog email to: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
def send_new_premium_email ( self , force = False ) :
2011-09-21 17:49:26 -07:00
if not self . user . email or not self . send_emails :
2011-09-19 08:56:16 -07:00
return
2024-04-24 09:43:56 -04:00
params = dict ( receiver_user_id = self . user . pk , email_type = " new_premium " )
2015-07-20 16:44:50 -07:00
try :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . get ( * * params )
2015-07-20 16:44:50 -07:00
if not force :
# Return if email already sent
return
except MSentEmail . DoesNotExist :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . create ( * * params )
2015-07-20 16:44:50 -07:00
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_new_premium.txt " , locals ( ) )
html = render_to_string ( " mail/email_new_premium.xhtml " , locals ( ) )
2022-03-17 16:54:40 -04:00
subject = " Thank you for subscribing to NewsBlur Premium! "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2011-09-19 08:56:16 -07:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
2011-09-23 18:13:16 -07:00
logging . user ( self . user , " ~BB~FM~SBSending email for new premium: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
2022-06-22 15:53:13 -04:00
def send_new_premium_archive_email ( self , total_story_count , pre_archive_count , force = False ) :
2022-04-18 13:29:13 -04:00
if not self . user . email :
2022-01-11 15:56:19 -05:00
return
2024-04-24 09:43:56 -04:00
params = dict ( receiver_user_id = self . user . pk , email_type = " new_premium_archive " )
2022-01-11 15:56:19 -05:00
try :
MSentEmail . objects . get ( * * params )
if not force :
# Return if email already sent
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BB~FMNot ~SBSending email for new premium archive: %s ( %s to %s stories) "
% ( self . user . email , pre_archive_count , total_story_count ) ,
)
2022-01-11 15:56:19 -05:00
return
except MSentEmail . DoesNotExist :
MSentEmail . objects . create ( * * params )
2022-05-05 16:03:14 -04:00
feed_count = UserSubscription . objects . filter ( user = self . user ) . count ( )
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_new_premium_archive.txt " , locals ( ) )
html = render_to_string ( " mail/email_new_premium_archive.xhtml " , locals ( ) )
2022-05-05 16:03:14 -04:00
if total_story_count > pre_archive_count :
subject = f " NewsBlur archive backfill is complete: from { pre_archive_count : , } to { total_story_count : , } stories "
else :
subject = f " NewsBlur archive backfill is complete: { total_story_count : , } stories "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2022-01-11 15:56:19 -05:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BB~FM~SBSending email for new premium archive: %s ( %s to %s stories) "
% ( self . user . email , pre_archive_count , total_story_count ) ,
)
2022-01-11 15:56:19 -05:00
def send_new_premium_pro_email ( self , force = False ) :
if not self . user . email or not self . send_emails :
return
2024-04-24 09:43:56 -04:00
params = dict ( receiver_user_id = self . user . pk , email_type = " new_premium_pro " )
2022-01-11 15:56:19 -05:00
try :
MSentEmail . objects . get ( * * params )
if not force :
# Return if email already sent
return
except MSentEmail . DoesNotExist :
MSentEmail . objects . create ( * * params )
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_new_premium_pro.txt " , locals ( ) )
html = render_to_string ( " mail/email_new_premium_pro.xhtml " , locals ( ) )
2022-01-11 15:56:19 -05:00
subject = " Thanks for subscribing to NewsBlur Premium Pro! "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2022-01-11 15:56:19 -05:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
2022-01-11 15:56:19 -05:00
logging . user ( self . user , " ~BB~FM~SBSending email for new premium pro: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
2011-09-22 09:23:42 -07:00
def send_forgot_password_email ( self , email = None ) :
if not self . user . email and not email :
2020-06-17 00:17:32 -04:00
print ( " Please provide an email address. " )
2011-09-22 09:23:42 -07:00
return
2024-04-24 09:43:56 -04:00
2011-09-22 09:23:42 -07:00
if not self . user . email and email :
self . user . email = email
self . user . save ( )
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_forgot_password.txt " , locals ( ) )
html = render_to_string ( " mail/email_forgot_password.xhtml " , locals ( ) )
2011-09-22 09:23:42 -07:00
subject = " Forgot your password on NewsBlur? "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2011-09-22 09:23:42 -07:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
2011-09-23 18:13:16 -07:00
logging . user ( self . user , " ~BB~FM~SBSending email for forgotten password: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
2013-05-13 18:03:17 -07:00
def send_new_user_queue_email ( self , force = False ) :
if not self . user . email :
2020-06-17 00:17:32 -04:00
print ( " Please provide an email address. " )
2013-05-13 18:03:17 -07:00
return
2024-04-24 09:43:56 -04:00
params = dict ( receiver_user_id = self . user . pk , email_type = " new_user_queue " )
2015-07-20 16:44:50 -07:00
try :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . get ( * * params )
2015-07-20 16:44:50 -07:00
if not force :
# Return if email already sent
return
except MSentEmail . DoesNotExist :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . create ( * * params )
2015-07-20 16:44:50 -07:00
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_new_user_queue.txt " , locals ( ) )
html = render_to_string ( " mail/email_new_user_queue.xhtml " , locals ( ) )
2013-05-13 18:03:17 -07:00
subject = " Your free account is now ready to go on NewsBlur "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2013-05-13 18:03:17 -07:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
2013-05-13 18:03:17 -07:00
logging . user ( self . user , " ~BB~FM~SBSending email for new user queue: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
2012-07-20 19:43:28 -07:00
def send_upload_opml_finished_email ( self , feed_count ) :
if not self . user . email :
2020-06-17 00:17:32 -04:00
print ( " Please provide an email address. " )
2012-07-20 19:43:28 -07:00
return
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_upload_opml_finished.txt " , locals ( ) )
html = render_to_string ( " mail/email_upload_opml_finished.xhtml " , locals ( ) )
2012-07-20 19:43:28 -07:00
subject = " Your OPML upload is complete. Get going with NewsBlur! "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2012-07-20 19:43:28 -07:00
msg . attach_alternative ( html , " text/html " )
msg . send ( )
2024-04-24 09:43:56 -04:00
2012-07-20 19:43:28 -07:00
logging . user ( self . user , " ~BB~FM~SBSending email for OPML upload: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
2013-04-02 15:41:50 -07:00
def send_import_reader_finished_email ( self , feed_count ) :
if not self . user . email :
2020-06-17 00:17:32 -04:00
print ( " Please provide an email address. " )
2013-04-02 15:41:50 -07:00
return
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_import_reader_finished.txt " , locals ( ) )
html = render_to_string ( " mail/email_import_reader_finished.xhtml " , locals ( ) )
2013-04-02 15:41:50 -07:00
subject = " Your Google Reader import is complete. Get going with NewsBlur! "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2013-04-02 15:41:50 -07:00
msg . attach_alternative ( html , " text/html " )
msg . send ( )
2024-04-24 09:43:56 -04:00
2013-04-02 15:41:50 -07:00
logging . user ( self . user , " ~BB~FM~SBSending email for Google Reader import: %s " % self . user . email )
2024-04-24 09:43:56 -04:00
2013-04-02 15:41:50 -07:00
def send_import_reader_starred_finished_email ( self , feed_count , starred_count ) :
if not self . user . email :
2020-06-17 00:17:32 -04:00
print ( " Please provide an email address. " )
2013-04-02 15:41:50 -07:00
return
2024-04-24 09:43:56 -04:00
user = self . user
text = render_to_string ( " mail/email_import_reader_starred_finished.txt " , locals ( ) )
html = render_to_string ( " mail/email_import_reader_starred_finished.xhtml " , locals ( ) )
2013-04-02 15:41:50 -07:00
subject = " Your Google Reader starred stories import is complete. Get going with NewsBlur! "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2013-04-02 15:41:50 -07:00
msg . attach_alternative ( html , " text/html " )
msg . send ( )
2024-04-24 09:43:56 -04:00
logging . user (
self . user , " ~BB~FM~SBSending email for Google Reader starred stories import: %s " % self . user . email
)
2012-08-09 19:45:08 -07:00
def send_launch_social_email ( self , force = False ) :
if not self . user . email or not self . send_emails :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~FM~SB~FRNot~FM sending launch social email for user, %s : %s "
% ( self . user . email and " opt-out: " or " blank " , self . user . email ) ,
)
2012-08-09 19:45:08 -07:00
return
2024-04-24 09:43:56 -04:00
params = dict ( receiver_user_id = self . user . pk , email_type = " launch_social " )
2015-07-20 16:44:50 -07:00
try :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . get ( * * params )
2015-07-20 16:44:50 -07:00
if not force :
# Return if email already sent
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~FM~SB~FRNot~FM sending launch social email for user, sent already: %s "
% self . user . email ,
)
2015-07-20 16:44:50 -07:00
return
except MSentEmail . DoesNotExist :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . create ( * * params )
2024-04-24 09:43:56 -04:00
delta = datetime . datetime . now ( ) - self . last_seen_on
2012-08-09 19:45:08 -07:00
months_ago = delta . days / 30
2024-04-24 09:43:56 -04:00
user = self . user
data = dict ( user = user , months_ago = months_ago )
text = render_to_string ( " mail/email_launch_social.txt " , data )
html = render_to_string ( " mail/email_launch_social.xhtml " , data )
2012-08-09 19:45:08 -07:00
subject = " NewsBlur is now a social news reader "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2012-08-09 19:45:08 -07:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BB~FM~SBSending launch social email for user: %s months, %s " % ( months_ago , self . user . email ) ,
)
2016-09-30 23:49:15 -07:00
def send_launch_turntouch_email ( self , force = False ) :
if not self . user . email or not self . send_emails :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~FM~SB~FRNot~FM sending launch TT email for user, %s : %s "
% ( self . user . email and " opt-out: " or " blank " , self . user . email ) ,
)
2016-09-30 23:49:15 -07:00
return
2024-04-24 09:43:56 -04:00
params = dict ( receiver_user_id = self . user . pk , email_type = " launch_turntouch " )
2016-09-30 23:49:15 -07:00
try :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . get ( * * params )
2016-09-30 23:49:15 -07:00
if not force :
# Return if email already sent
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~FM~SB~FRNot~FM sending launch social email for user, sent already: %s "
% self . user . email ,
)
2016-09-30 23:49:15 -07:00
return
except MSentEmail . DoesNotExist :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . create ( * * params )
2024-04-24 09:43:56 -04:00
delta = datetime . datetime . now ( ) - self . last_seen_on
2016-09-30 23:49:15 -07:00
months_ago = delta . days / 30
2024-04-24 09:43:56 -04:00
user = self . user
data = dict ( user = user , months_ago = months_ago )
text = render_to_string ( " mail/email_launch_turntouch.txt " , data )
html = render_to_string ( " mail/email_launch_turntouch.xhtml " , data )
2016-09-30 23:49:15 -07:00
subject = " Introducing Turn Touch for NewsBlur "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2016-09-30 23:49:15 -07:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BB~FM~SBSending launch TT email for user: %s months, %s " % ( months_ago , self . user . email ) ,
)
2017-03-08 18:04:57 -08:00
def send_launch_turntouch_end_email ( self , force = False ) :
if not self . user . email or not self . send_emails :
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~FM~SB~FRNot~FM sending launch TT end email for user, %s : %s "
% ( self . user . email and " opt-out: " or " blank " , self . user . email ) ,
)
2017-03-08 18:04:57 -08:00
return
2024-04-24 09:43:56 -04:00
params = dict ( receiver_user_id = self . user . pk , email_type = " launch_turntouch_end " )
2017-03-08 18:04:57 -08:00
try :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . get ( * * params )
2017-03-08 18:04:57 -08:00
if not force :
# Return if email already sent
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~FM~SB~FRNot~FM sending launch TT end email for user, sent already: %s "
% self . user . email ,
)
2017-03-08 18:04:57 -08:00
return
except MSentEmail . DoesNotExist :
2017-05-18 16:59:35 -07:00
MSentEmail . objects . create ( * * params )
2024-04-24 09:43:56 -04:00
delta = datetime . datetime . now ( ) - self . last_seen_on
2017-03-08 18:04:57 -08:00
months_ago = delta . days / 30
2024-04-24 09:43:56 -04:00
user = self . user
data = dict ( user = user , months_ago = months_ago )
text = render_to_string ( " mail/email_launch_turntouch_end.txt " , data )
html = render_to_string ( " mail/email_launch_turntouch_end.xhtml " , data )
2017-03-08 18:04:57 -08:00
subject = " Last day to back Turn Touch: NewsBlur ' s beautiful remote "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2017-03-08 18:04:57 -08:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
logging . user (
self . user ,
" ~BB~FM~SBSending launch TT end email for user: %s months, %s " % ( months_ago , self . user . email ) ,
)
2015-05-18 14:13:48 -07:00
def grace_period_email_sent ( self , force = False ) :
2024-04-24 09:43:56 -04:00
emails_sent = MSentEmail . objects . filter (
receiver_user_id = self . user . pk , email_type = " premium_expire_grace "
)
2012-12-05 11:56:55 -08:00
day_ago = datetime . datetime . now ( ) - datetime . timedelta ( days = 360 )
for email in emails_sent :
2014-05-29 12:19:26 -07:00
if email . date_sent > day_ago and not force :
2013-01-07 17:43:05 -08:00
logging . user ( self . user , " ~SN~FMNot sending premium expire grace email, already sent before. " )
2015-05-18 14:13:48 -07:00
return True
2024-04-24 09:43:56 -04:00
2015-05-18 14:13:48 -07:00
def send_premium_expire_grace_period_email ( self , force = False ) :
if not self . user . email :
2024-04-24 09:43:56 -04:00
logging . user (
self . user , " ~FM~SB~FRNot~FM~SN sending premium expire grace for user: %s " % ( self . user )
)
2015-05-18 14:13:48 -07:00
return
if self . grace_period_email_sent ( force = force ) :
return
2024-04-24 09:43:56 -04:00
2017-09-18 08:34:49 -07:00
if self . premium_expire and self . premium_expire < datetime . datetime . now ( ) :
2015-05-18 14:13:48 -07:00
self . premium_expire = datetime . datetime . now ( )
2012-12-05 11:56:55 -08:00
self . save ( )
2024-04-24 09:43:56 -04:00
delta = datetime . datetime . now ( ) - self . last_seen_on
2024-02-26 14:42:17 -05:00
months_ago = round ( delta . days / 30 )
2024-04-24 09:43:56 -04:00
user = self . user
data = dict ( user = user , months_ago = months_ago )
text = render_to_string ( " mail/email_premium_expire_grace.txt " , data )
html = render_to_string ( " mail/email_premium_expire_grace.xhtml " , data )
2012-12-05 11:56:55 -08:00
subject = " Your premium account on NewsBlur has one more month! "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2012-12-05 11:56:55 -08:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
MSentEmail . record ( receiver_user_id = self . user . pk , email_type = " premium_expire_grace " )
logging . user (
self . user ,
" ~BB~FM~SBSending premium expire grace email for user: %s months, %s "
% ( months_ago , self . user . email ) ,
)
2012-12-05 11:56:55 -08:00
def send_premium_expire_email ( self , force = False ) :
if not self . user . email :
logging . user ( self . user , " ~FM~SB~FRNot~FM sending premium expire for user: %s " % ( self . user ) )
return
2024-04-24 09:43:56 -04:00
emails_sent = MSentEmail . objects . filter ( receiver_user_id = self . user . pk , email_type = " premium_expire " )
2012-12-05 11:56:55 -08:00
day_ago = datetime . datetime . now ( ) - datetime . timedelta ( days = 360 )
for email in emails_sent :
2014-05-29 12:19:26 -07:00
if email . date_sent > day_ago and not force :
2013-01-07 17:43:05 -08:00
logging . user ( self . user , " ~FM~SBNot sending premium expire email, already sent before. " )
2012-12-05 11:56:55 -08:00
return
2024-04-24 09:43:56 -04:00
delta = datetime . datetime . now ( ) - self . last_seen_on
2024-02-26 14:42:17 -05:00
months_ago = round ( delta . days / 30 )
2024-04-24 09:43:56 -04:00
user = self . user
data = dict ( user = user , months_ago = months_ago )
text = render_to_string ( " mail/email_premium_expire.txt " , data )
html = render_to_string ( " mail/email_premium_expire.xhtml " , data )
2012-12-05 11:56:55 -08:00
subject = " Your premium account on NewsBlur has expired "
2024-04-24 09:43:56 -04:00
msg = EmailMultiAlternatives (
subject ,
text ,
from_email = " NewsBlur < %s > " % settings . HELLO_EMAIL ,
to = [ " %s < %s > " % ( user , user . email ) ] ,
)
2012-12-05 11:56:55 -08:00
msg . attach_alternative ( html , " text/html " )
2022-03-17 16:54:40 -04:00
msg . send ( )
2024-04-24 09:43:56 -04:00
MSentEmail . record ( receiver_user_id = self . user . pk , email_type = " premium_expire " )
logging . user (
self . user ,
" ~BB~FM~SBSending premium expire email for user: %s months, %s " % ( months_ago , self . user . email ) ,
)
2011-09-19 09:46:36 -07:00
def autologin_url ( self , next = None ) :
2024-04-24 09:43:56 -04:00
return reverse ( " autologin " , kwargs = { " username " : self . user . username , " secret " : self . secret_token } ) + (
" ? " + next + " =1 " if next else " "
)
2015-01-05 17:06:41 -08:00
@classmethod
def doublecheck_paypal_payments ( cls , days = 14 ) :
2024-04-24 09:43:56 -04:00
payments = PayPalIPN . objects . filter (
txn_type = " subscr_payment " , updated_at__gte = datetime . datetime . now ( ) - datetime . timedelta ( days )
) . order_by ( " -created_at " )
2015-01-05 17:06:41 -08:00
for payment in payments :
try :
profile = Profile . objects . get ( user__username = payment . custom )
except Profile . DoesNotExist :
logging . debug ( " ---> ~FRCouldn ' t find user: ~SB~FC %s " % payment . custom )
continue
2019-09-09 21:17:10 -04:00
profile . setup_premium_history ( )
2024-04-24 09:43:56 -04:00
2018-05-01 14:18:59 -07:00
class StripeIds ( models . Model ) :
2024-04-24 09:43:56 -04:00
user = models . ForeignKey ( User , related_name = " stripe_ids " , on_delete = models . CASCADE , null = True )
2018-05-01 14:18:59 -07:00
stripe_id = models . CharField ( max_length = 24 , blank = True , null = True )
2020-06-30 20:50:30 -04:00
def __str__ ( self ) :
2018-05-01 14:18:59 -07:00
return " %s : %s " % ( self . user . username , self . stripe_id )
2022-02-08 12:49:40 -05:00
class PaypalIds ( models . Model ) :
2024-04-24 09:43:56 -04:00
user = models . ForeignKey ( User , related_name = " paypal_ids " , on_delete = models . CASCADE , null = True )
2022-02-08 12:49:40 -05:00
paypal_sub_id = models . CharField ( max_length = 24 , blank = True , null = True )
def __str__ ( self ) :
return " %s : %s " % ( self . user . username , self . paypal_sub_id )
2024-04-24 09:43:56 -04:00
2010-05-11 21:36:17 -04:00
def create_profile ( sender , instance , created , * * kwargs ) :
if created :
Profile . objects . create ( user = instance )
2010-06-11 20:55:38 -04:00
else :
Profile . objects . get_or_create ( user = instance )
2024-04-24 09:43:56 -04:00
2010-10-16 18:52:52 -04:00
post_save . connect ( create_profile , sender = User )
2015-01-15 12:40:17 -08:00
def paypal_signup ( sender , * * kwargs ) :
2010-10-16 18:52:52 -04:00
ipn_obj = sender
2022-07-01 12:17:14 -04:00
user = None
2022-07-03 10:42:01 -04:00
if ipn_obj . custom :
try :
user = User . objects . get ( username__iexact = ipn_obj . custom )
except User . DoesNotExist :
pass
2022-07-01 12:17:14 -04:00
2022-07-03 10:42:01 -04:00
if not user and ipn_obj . payer_email :
2021-08-03 16:04:56 -04:00
try :
user = User . objects . get ( email__iexact = ipn_obj . payer_email )
except User . DoesNotExist :
2022-07-01 12:17:14 -04:00
pass
2024-04-24 09:43:56 -04:00
2022-07-03 10:42:01 -04:00
if not user and ipn_obj . custom :
2022-07-01 12:17:14 -04:00
try :
user = User . objects . get ( pk = ipn_obj . custom )
except User . DoesNotExist :
pass
2022-07-03 10:42:01 -04:00
if not user and ipn_obj . subscr_id :
2022-07-01 12:17:14 -04:00
try :
user = PaypalIds . objects . get ( paypal_sub_id = ipn_obj . subscr_id ) . user
except PaypalIds . DoesNotExist :
pass
if not user :
2024-04-24 09:43:56 -04:00
logging . debug (
" ---> Paypal subscription not found during paypal_signup: %s / %s "
% ( ipn_obj . payer_email , ipn_obj . custom )
)
2022-07-01 12:17:14 -04:00
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2021-01-05 14:55:53 -05:00
2015-01-15 12:40:17 -08:00
logging . user ( user , " ~BC~SB~FBPaypal subscription signup " )
2011-10-19 09:40:31 -07:00
try :
if not user . email :
user . email = ipn_obj . payer_email
user . save ( )
2015-01-15 12:40:17 -08:00
except :
pass
user . profile . activate_premium ( )
2016-03-20 17:55:44 -07:00
user . profile . cancel_premium_stripe ( )
2022-02-09 12:26:35 -05:00
# user.profile.cancel_premium_paypal(second_most_recent_only=True)
2022-07-01 12:17:14 -04:00
# assert False, "Shouldn't be here anymore as the new Paypal REST API uses webhooks"
2024-04-24 09:43:56 -04:00
2020-06-24 16:59:43 -04:00
valid_ipn_received . connect ( paypal_signup )
2015-01-15 12:40:17 -08:00
2024-04-24 09:43:56 -04:00
2015-01-15 12:40:17 -08:00
def paypal_payment_history_sync ( sender , * * kwargs ) :
ipn_obj = sender
try :
user = User . objects . get ( username__iexact = ipn_obj . custom )
except User . DoesNotExist :
2021-08-03 16:04:56 -04:00
try :
user = User . objects . get ( email__iexact = ipn_obj . payer_email )
except User . DoesNotExist :
2024-04-24 09:43:56 -04:00
logging . debug (
" ---> Paypal subscription not found during flagging: %s / %s "
% ( ipn_obj . payer_email , ipn_obj . custom )
)
2021-08-03 16:04:56 -04:00
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2021-01-05 14:55:53 -05:00
2015-01-15 12:40:17 -08:00
logging . user ( user , " ~BC~SB~FBPaypal subscription payment " )
try :
2019-09-09 21:17:10 -04:00
user . profile . setup_premium_history ( )
2012-12-03 15:17:35 -08:00
except :
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2024-04-24 09:43:56 -04:00
2020-06-24 16:59:43 -04:00
valid_ipn_received . connect ( paypal_payment_history_sync )
2014-12-04 15:47:19 -08:00
2024-04-24 09:43:56 -04:00
2015-01-15 12:40:17 -08:00
def paypal_payment_was_flagged ( sender , * * kwargs ) :
2014-12-04 15:47:19 -08:00
ipn_obj = sender
try :
user = User . objects . get ( username__iexact = ipn_obj . custom )
except User . DoesNotExist :
2021-08-03 16:04:56 -04:00
try :
2015-02-09 13:51:06 -08:00
user = User . objects . get ( email__iexact = ipn_obj . payer_email )
2021-08-03 16:04:56 -04:00
except User . DoesNotExist :
2024-04-24 09:43:56 -04:00
logging . debug (
" ---> Paypal subscription not found during flagging: %s / %s "
% ( ipn_obj . payer_email , ipn_obj . custom )
)
2021-08-03 16:04:56 -04:00
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2024-04-24 09:43:56 -04:00
2014-12-04 15:47:19 -08:00
try :
2019-09-09 21:17:10 -04:00
user . profile . setup_premium_history ( )
2015-02-19 10:50:06 -08:00
logging . user ( user , " ~BC~SB~FBPaypal subscription payment flagged " )
2014-12-04 15:47:19 -08:00
except :
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2024-04-24 09:43:56 -04:00
2020-06-24 16:59:43 -04:00
invalid_ipn_received . connect ( paypal_payment_was_flagged )
2015-01-15 12:40:17 -08:00
2024-04-24 09:43:56 -04:00
2022-01-24 17:33:11 -05:00
def stripe_checkout_session_completed ( sender , full_json , * * kwargs ) :
2024-04-24 09:43:56 -04:00
newsblur_user_id = full_json [ " data " ] [ " object " ] [ " metadata " ] [ " newsblur_user_id " ]
stripe_id = full_json [ " data " ] [ " object " ] [ " customer " ]
2022-01-24 17:23:25 -05:00
profile = None
try :
profile = Profile . objects . get ( stripe_id = stripe_id )
except Profile . DoesNotExist :
pass
2024-04-24 09:43:56 -04:00
2022-01-24 17:23:25 -05:00
if not profile :
try :
profile = User . objects . get ( pk = int ( newsblur_user_id ) ) . profile
profile . stripe_id = stripe_id
profile . save ( )
except User . DoesNotExist :
pass
2024-04-24 09:43:56 -04:00
2022-01-24 17:23:25 -05:00
if profile :
logging . user ( profile . user , " ~BC~SB~FBStripe checkout subscription signup " )
profile . retrieve_stripe_ids ( )
else :
2022-01-24 17:33:11 -05:00
logging . user ( profile . user , " ~BR~SB~FRCouldn ' t find Stripe user: ~FW %s " % full_json )
2022-01-24 17:23:25 -05:00
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2024-04-24 09:43:56 -04:00
2022-01-24 17:33:11 -05:00
zebra_webhook_checkout_session_completed . connect ( stripe_checkout_session_completed )
2022-01-24 17:23:25 -05:00
2024-04-24 09:43:56 -04:00
2012-02-28 17:39:02 -08:00
def stripe_signup ( sender , full_json , * * kwargs ) :
2024-04-24 09:43:56 -04:00
stripe_id = full_json [ " data " ] [ " object " ] [ " customer " ]
plan_id = full_json [ " data " ] [ " object " ] [ " plan " ] [ " id " ]
2012-07-27 12:46:37 -07:00
try :
profile = Profile . objects . get ( stripe_id = stripe_id )
2014-12-04 15:15:15 -08:00
logging . user ( profile . user , " ~BC~SB~FBStripe subscription signup " )
2024-04-24 09:43:56 -04:00
if plan_id == Profile . plan_to_stripe_price ( " premium " ) :
2022-01-24 17:23:25 -05:00
profile . activate_premium ( )
2024-04-24 09:43:56 -04:00
elif plan_id == Profile . plan_to_stripe_price ( " archive " ) :
2022-02-17 12:27:49 -05:00
profile . activate_archive ( )
2024-04-24 09:43:56 -04:00
elif plan_id == Profile . plan_to_stripe_price ( " pro " ) :
2022-02-17 12:27:49 -05:00
profile . activate_pro ( )
2016-03-20 17:55:44 -07:00
profile . cancel_premium_paypal ( )
2018-05-01 14:18:59 -07:00
profile . retrieve_stripe_ids ( )
2012-07-27 12:46:37 -07:00
except Profile . DoesNotExist :
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2024-04-24 09:43:56 -04:00
2012-02-27 21:46:34 -08:00
zebra_webhook_customer_subscription_created . connect ( stripe_signup )
2024-04-24 09:43:56 -04:00
2022-01-26 15:51:26 -05:00
def stripe_subscription_updated ( sender , full_json , * * kwargs ) :
2024-04-24 09:43:56 -04:00
stripe_id = full_json [ " data " ] [ " object " ] [ " customer " ]
plan_id = full_json [ " data " ] [ " object " ] [ " plan " ] [ " id " ]
2022-01-26 15:51:26 -05:00
try :
profile = Profile . objects . get ( stripe_id = stripe_id )
2024-04-24 09:43:56 -04:00
active = (
not full_json [ " data " ] [ " object " ] [ " cancel_at " ] and full_json [ " data " ] [ " object " ] [ " plan " ] [ " active " ]
)
logging . user (
profile . user , " ~BC~SB~FBStripe subscription updated: %s " % " active " if active else " cancelled "
)
2022-02-16 13:43:53 -05:00
if active :
2024-04-24 09:43:56 -04:00
if plan_id == Profile . plan_to_stripe_price ( " premium " ) :
2022-02-16 13:43:53 -05:00
profile . activate_premium ( )
2024-04-24 09:43:56 -04:00
elif plan_id == Profile . plan_to_stripe_price ( " archive " ) :
2022-02-17 12:27:49 -05:00
profile . activate_archive ( )
2024-04-24 09:43:56 -04:00
elif plan_id == Profile . plan_to_stripe_price ( " pro " ) :
2022-02-17 12:27:49 -05:00
profile . activate_pro ( )
2022-02-16 13:43:53 -05:00
profile . cancel_premium_paypal ( )
profile . retrieve_stripe_ids ( )
else :
profile . setup_premium_history ( )
2022-01-26 15:51:26 -05:00
except Profile . DoesNotExist :
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2024-04-24 09:43:56 -04:00
2022-01-26 15:51:26 -05:00
zebra_webhook_customer_subscription_updated . connect ( stripe_subscription_updated )
2024-04-24 09:43:56 -04:00
2012-12-03 15:17:35 -08:00
def stripe_payment_history_sync ( sender , full_json , * * kwargs ) :
2024-04-24 09:43:56 -04:00
stripe_id = full_json [ " data " ] [ " object " ] [ " customer " ]
2012-12-03 15:17:35 -08:00
try :
profile = Profile . objects . get ( stripe_id = stripe_id )
2014-12-04 15:15:15 -08:00
logging . user ( profile . user , " ~BC~SB~FBStripe subscription payment " )
2019-09-09 21:17:10 -04:00
profile . setup_premium_history ( )
2012-12-03 15:17:35 -08:00
except Profile . DoesNotExist :
2024-04-24 09:43:56 -04:00
return { " code " : - 1 , " message " : " User doesn ' t exist. " }
2012-12-03 15:17:35 -08:00
zebra_webhook_charge_succeeded . connect ( stripe_payment_history_sync )
2022-01-26 15:51:26 -05:00
zebra_webhook_charge_refunded . connect ( stripe_payment_history_sync )
2012-12-03 15:17:35 -08:00
2024-04-24 09:43:56 -04:00
2013-05-06 15:12:18 -07:00
def change_password ( user , old_password , new_password , only_check = False ) :
2010-11-08 12:09:55 -05:00
user_db = authenticate ( username = user . username , password = old_password )
if user_db is None :
2013-03-20 18:36:15 -07:00
blank = blank_authenticate ( user . username )
2013-05-06 15:12:18 -07:00
if blank and not only_check :
user . set_password ( new_password or user . username )
2013-03-20 18:36:15 -07:00
user . save ( )
if user_db is None :
user_db = authenticate ( username = user . username , password = user . username )
2024-04-24 09:43:56 -04:00
2013-03-20 18:36:15 -07:00
if not user_db :
2010-11-08 12:09:55 -05:00
return - 1
else :
2013-05-06 15:12:18 -07:00
if not only_check :
user_db . set_password ( new_password )
user_db . save ( )
2012-07-09 13:55:29 -07:00
return 1
2013-04-05 19:23:42 -07:00
2024-04-24 09:43:56 -04:00
2013-03-20 18:36:15 -07:00
def blank_authenticate ( username , password = " " ) :
try :
2013-05-06 15:12:18 -07:00
user = User . objects . get ( username__iexact = username )
2013-03-20 18:36:15 -07:00
except User . DoesNotExist :
return
2024-04-24 09:43:56 -04:00
2013-03-20 18:36:15 -07:00
if user . password == " ! " :
return user
2024-04-24 09:43:56 -04:00
algorithm , salt , hash = user . password . split ( " $ " , 2 )
encoded_blank = hashlib . sha1 ( ( salt + password ) . encode ( encoding = " utf-8 " ) ) . hexdigest ( )
2013-04-05 19:23:42 -07:00
encoded_username = authenticate ( username = username , password = username )
if encoded_blank == hash or encoded_username == user :
2013-03-20 18:36:15 -07:00
return user
2016-09-30 23:49:15 -07:00
2024-04-24 09:43:56 -04:00
2016-09-30 23:49:15 -07:00
# Unfinished
class MEmailUnsubscribe ( mongo . Document ) :
user_id = mongo . IntField ( )
email_type = mongo . StringField ( )
date = mongo . DateTimeField ( default = datetime . datetime . now )
2024-04-24 09:43:56 -04:00
EMAIL_TYPE_FOLLOWS = " follows "
EMAIL_TYPE_REPLIES = " replies "
EMAIL_TYOE_PRODUCT = " product "
2016-09-30 23:49:15 -07:00
meta = {
2024-04-24 09:43:56 -04:00
" collection " : " email_unsubscribes " ,
" allow_inheritance " : False ,
" indexes " : [
" user_id " ,
{
" fields " : [ " user_id " , " email_type " ] ,
" unique " : True ,
} ,
] ,
2016-09-30 23:49:15 -07:00
}
2024-04-24 09:43:56 -04:00
2020-06-30 20:50:30 -04:00
def __str__ ( self ) :
2016-09-30 23:49:15 -07:00
return " %s unsubscribed from %s on %s " % ( self . user_id , self . email_type , self . date )
2024-04-24 09:43:56 -04:00
2016-09-30 23:49:15 -07:00
@classmethod
def user ( cls , user_id ) :
unsubs = cls . objects ( user_id = user_id )
return unsubs
2024-04-24 09:43:56 -04:00
2016-09-30 23:49:15 -07:00
@classmethod
def unsubscribe ( cls , user_id , email_type ) :
cls . objects . create ( )
2012-07-09 13:55:29 -07:00
class MSentEmail ( mongo . Document ) :
sending_user_id = mongo . IntField ( )
receiver_user_id = mongo . IntField ( )
email_type = mongo . StringField ( )
date_sent = mongo . DateTimeField ( default = datetime . datetime . now )
2024-04-24 09:43:56 -04:00
2012-07-09 13:55:29 -07:00
meta = {
2024-04-24 09:43:56 -04:00
" collection " : " sent_emails " ,
" allow_inheritance " : False ,
" indexes " : [ " sending_user_id " , " receiver_user_id " , " email_type " ] ,
2012-07-09 13:55:29 -07:00
}
2024-04-24 09:43:56 -04:00
2020-06-30 20:50:30 -04:00
def __str__ ( self ) :
2022-07-01 15:57:09 -04:00
sender_user = self . sending_user_id
if sender_user :
sender_user = User . objects . get ( pk = self . sending_user_id )
receiver_user = self . receiver_user_id
if receiver_user :
receiver_user = User . objects . get ( pk = self . receiver_user_id )
2024-04-24 09:43:56 -04:00
return " %s sent %s email to %s %s " % (
sender_user ,
self . email_type ,
receiver_user ,
receiver_user . profile if receiver_user else receiver_user ,
)
2012-07-09 13:55:29 -07:00
@classmethod
2012-12-05 13:10:11 -08:00
def record ( cls , email_type , receiver_user_id , sending_user_id = None ) :
2024-04-24 09:43:56 -04:00
cls . objects . create (
email_type = email_type , receiver_user_id = receiver_user_id , sending_user_id = sending_user_id
)
2012-12-03 14:35:21 -08:00
class PaymentHistory ( models . Model ) :
2024-04-24 09:43:56 -04:00
user = models . ForeignKey ( User , related_name = " payments " , on_delete = models . CASCADE )
2012-12-03 16:12:13 -08:00
payment_date = models . DateTimeField ( )
2012-12-03 14:35:21 -08:00
payment_amount = models . IntegerField ( )
payment_provider = models . CharField ( max_length = 20 )
2017-11-15 17:45:38 -08:00
payment_identifier = models . CharField ( max_length = 100 , null = True )
2022-04-08 15:07:58 -04:00
refunded = models . BooleanField ( blank = True , null = True )
2024-04-24 09:43:56 -04:00
2020-06-30 20:50:30 -04:00
def __str__ ( self ) :
2024-04-24 09:43:56 -04:00
return " [ %s ] $ %s / %s %s " % (
self . payment_date . strftime ( " % Y- % m- %d " ) ,
self . payment_amount ,
self . payment_provider ,
" <REFUNDED> " if self . refunded else " " ,
)
2012-12-03 14:35:21 -08:00
class Meta :
2024-04-24 09:43:56 -04:00
ordering = [ " -payment_date " ]
2013-06-12 13:52:43 -07:00
def canonical ( self ) :
2012-12-03 15:03:47 -08:00
return {
2024-04-24 09:43:56 -04:00
" payment_date " : self . payment_date . strftime ( " % Y- % m- %d " ) ,
" payment_amount " : self . payment_amount ,
" payment_provider " : self . payment_provider ,
" refunded " : self . refunded ,
2013-02-15 13:47:45 -08:00
}
2024-04-24 09:43:56 -04:00
2013-02-15 13:47:45 -08:00
@classmethod
2016-04-18 14:58:49 -07:00
def report ( cls , months = 26 ) :
2018-04-17 19:13:44 -07:00
output = " "
2024-04-24 09:43:56 -04:00
2018-04-17 19:13:44 -07:00
def _counter ( start_date , end_date , output , payments = None ) :
2017-12-14 15:38:24 -08:00
if not payments :
2024-04-24 09:43:56 -04:00
payments = PaymentHistory . objects . filter (
payment_date__gte = start_date , payment_date__lte = end_date
)
payments = payments . aggregate (
avg = Avg ( " payment_amount " ) , sum = Sum ( " payment_amount " ) , count = Count ( " user " )
)
2018-04-17 19:13:44 -07:00
output + = " %s - %02d - %02d - %s - %02d - %02d : \t $ %.2f \t $ %-6s \t %-4s \n " % (
2024-04-24 09:43:56 -04:00
start_date . year ,
start_date . month ,
start_date . day ,
end_date . year ,
end_date . month ,
end_date . day ,
round ( payments [ " avg " ] if payments [ " avg " ] else 0 , 2 ) ,
payments [ " sum " ] if payments [ " sum " ] else 0 ,
payments [ " count " ] ,
)
2018-04-17 19:13:44 -07:00
return payments , output
2013-05-13 16:17:49 -07:00
2018-04-17 19:13:44 -07:00
output + = " \n Monthly Totals: \n "
2020-06-17 00:17:32 -04:00
for m in reversed ( list ( range ( months ) ) ) :
2015-04-16 21:15:30 -07:00
now = datetime . datetime . now ( )
2024-04-24 09:43:56 -04:00
start_date = datetime . datetime ( now . year , now . month , 1 ) - dateutil . relativedelta . relativedelta (
months = m
)
2015-04-16 21:15:30 -07:00
end_time = start_date + datetime . timedelta ( days = 31 )
end_date = datetime . datetime ( end_time . year , end_time . month , 1 ) - datetime . timedelta ( seconds = 1 )
2018-04-17 19:13:44 -07:00
total , output = _counter ( start_date , end_date , output )
2024-04-24 09:43:56 -04:00
total = total [ " sum " ]
2015-04-16 22:29:36 -07:00
2018-04-17 19:13:44 -07:00
output + = " \n MTD Totals: \n "
2016-05-05 19:09:09 +08:00
years = datetime . datetime . now ( ) . year - 2009
2017-12-14 15:47:22 -08:00
this_mtd_avg = 0
last_mtd_avg = 0
2017-12-14 15:38:24 -08:00
last_mtd_sum = 0
this_mtd_sum = 0
last_mtd_count = 0
this_mtd_count = 0
2020-06-17 00:17:32 -04:00
for y in reversed ( list ( range ( years ) ) ) :
2016-05-05 19:09:09 +08:00
now = datetime . datetime . now ( )
2024-04-24 09:43:56 -04:00
start_date = datetime . datetime ( now . year , now . month , 1 ) - dateutil . relativedelta . relativedelta (
years = y
)
2017-12-14 15:38:24 -08:00
end_date = now - dateutil . relativedelta . relativedelta ( years = y )
2024-04-24 09:43:56 -04:00
if end_date > now :
end_date = now
2018-04-17 19:13:44 -07:00
count , output = _counter ( start_date , end_date , output )
2017-12-14 15:38:24 -08:00
if end_date . year != now . year :
2024-04-24 09:43:56 -04:00
last_mtd_avg = count [ " avg " ] or 0
last_mtd_sum = count [ " sum " ] or 0
last_mtd_count = count [ " count " ]
2017-12-14 15:38:24 -08:00
else :
2024-04-24 09:43:56 -04:00
this_mtd_avg = count [ " avg " ] or 0
this_mtd_sum = count [ " sum " ] or 0
this_mtd_count = count [ " count " ]
2016-05-05 19:09:09 +08:00
2018-04-17 19:13:44 -07:00
output + = " \n Current Month Totals: \n "
2016-05-05 19:05:06 +08:00
years = datetime . datetime . now ( ) . year - 2009
2017-12-14 15:47:22 -08:00
last_month_avg = 0
2017-12-14 15:38:24 -08:00
last_month_sum = 0
last_month_count = 0
2020-06-17 00:17:32 -04:00
for y in reversed ( list ( range ( years ) ) ) :
2016-05-05 19:05:06 +08:00
now = datetime . datetime . now ( )
2024-04-24 09:43:56 -04:00
start_date = datetime . datetime ( now . year , now . month , 1 ) - dateutil . relativedelta . relativedelta (
years = y
)
2017-12-14 15:38:24 -08:00
end_time = start_date + datetime . timedelta ( days = 31 )
end_date = datetime . datetime ( end_time . year , end_time . month , 1 ) - datetime . timedelta ( seconds = 1 )
if end_date > now :
2024-04-24 09:43:56 -04:00
payments = {
" avg " : this_mtd_avg / ( max ( 1 , last_mtd_avg ) / float ( max ( 1 , last_month_avg ) ) ) ,
" sum " : int ( round ( this_mtd_sum / ( max ( 1 , last_mtd_sum ) / float ( max ( 1 , last_month_sum ) ) ) ) ) ,
" count " : int (
round ( this_mtd_count / ( max ( 1 , last_mtd_count ) / float ( max ( 1 , last_month_count ) ) ) )
) ,
}
2018-04-17 19:13:44 -07:00
_ , output = _counter ( start_date , end_date , output , payments = payments )
2017-12-14 15:38:24 -08:00
else :
2018-04-17 19:13:44 -07:00
count , output = _counter ( start_date , end_date , output )
2024-04-24 09:43:56 -04:00
last_month_avg = count [ " avg " ]
last_month_sum = count [ " sum " ]
last_month_count = count [ " count " ]
2016-05-05 19:05:06 +08:00
2018-04-17 19:13:44 -07:00
output + = " \n YTD Totals: \n "
2015-04-16 21:15:30 -07:00
years = datetime . datetime . now ( ) . year - 2009
2017-12-14 16:06:22 -08:00
this_ytd_avg = 0
last_ytd_avg = 0
this_ytd_sum = 0
last_ytd_sum = 0
this_ytd_count = 0
last_ytd_count = 0
2020-06-17 00:17:32 -04:00
for y in reversed ( list ( range ( years ) ) ) :
2015-04-16 21:15:30 -07:00
now = datetime . datetime . now ( )
start_date = datetime . datetime ( now . year , 1 , 1 ) - dateutil . relativedelta . relativedelta ( years = y )
2017-12-14 16:06:22 -08:00
end_date = now - dateutil . relativedelta . relativedelta ( years = y )
2018-04-17 19:13:44 -07:00
count , output = _counter ( start_date , end_date , output )
2017-12-14 16:12:45 -08:00
if end_date . year != now . year :
2024-04-24 09:43:56 -04:00
last_ytd_avg = count [ " avg " ] or 0
last_ytd_sum = count [ " sum " ] or 0
last_ytd_count = count [ " count " ]
2017-12-14 16:06:22 -08:00
else :
2024-04-24 09:43:56 -04:00
this_ytd_avg = count [ " avg " ] or 0
this_ytd_sum = count [ " sum " ] or 0
this_ytd_count = count [ " count " ]
2016-04-18 14:58:49 -07:00
2018-04-17 19:13:44 -07:00
output + = " \n Yearly Totals: \n "
2016-04-18 14:58:49 -07:00
years = datetime . datetime . now ( ) . year - 2009
2017-12-14 16:06:22 -08:00
last_year_avg = 0
last_year_sum = 0
last_year_count = 0
2018-04-17 19:16:55 -07:00
annual = 0
2020-06-17 00:17:32 -04:00
for y in reversed ( list ( range ( years ) ) ) :
2016-04-18 14:58:49 -07:00
now = datetime . datetime . now ( )
start_date = datetime . datetime ( now . year , 1 , 1 ) - dateutil . relativedelta . relativedelta ( years = y )
2024-04-24 09:43:56 -04:00
end_date = (
datetime . datetime ( now . year , 1 , 1 )
- dateutil . relativedelta . relativedelta ( years = y - 1 )
- datetime . timedelta ( seconds = 1 )
)
2017-12-14 16:06:22 -08:00
if end_date > now :
2024-04-24 09:43:56 -04:00
payments = {
" avg " : this_ytd_avg / ( max ( 1 , last_ytd_avg ) / float ( max ( 1 , last_year_avg ) ) ) ,
" sum " : int ( round ( this_ytd_sum / ( max ( 1 , last_ytd_sum ) / float ( max ( 1 , last_year_sum ) ) ) ) ) ,
" count " : int (
round ( this_ytd_count / ( max ( 1 , last_ytd_count ) / float ( max ( 1 , last_year_count ) ) ) )
) ,
}
2018-04-17 19:16:55 -07:00
count , output = _counter ( start_date , end_date , output , payments = payments )
2024-04-24 09:43:56 -04:00
annual = count [ " sum " ]
2017-12-14 16:06:22 -08:00
else :
2018-04-17 19:13:44 -07:00
count , output = _counter ( start_date , end_date , output )
2024-04-24 09:43:56 -04:00
last_year_avg = count [ " avg " ] or 0
last_year_sum = count [ " sum " ] or 0
last_year_count = count [ " count " ]
total = cls . objects . all ( ) . aggregate ( sum = Sum ( " payment_amount " ) )
output + = " \n Total: $ %s \n " % total [ " sum " ]
2020-06-17 00:17:32 -04:00
print ( output )
2024-04-24 09:43:56 -04:00
return { " annual " : annual , " output " : output }
2014-11-06 14:55:27 -08:00
2015-06-30 16:05:58 -07:00
class MGiftCode ( mongo . Document ) :
gifting_user_id = mongo . IntField ( )
receiving_user_id = mongo . IntField ( )
gift_code = mongo . StringField ( max_length = 12 )
duration_days = mongo . IntField ( )
payment_amount = mongo . IntField ( )
created_date = mongo . DateTimeField ( default = datetime . datetime . now )
2024-04-24 09:43:56 -04:00
2015-06-30 16:05:58 -07:00
meta = {
2024-04-24 09:43:56 -04:00
" collection " : " gift_codes " ,
" allow_inheritance " : False ,
" indexes " : [ " gifting_user_id " , " receiving_user_id " , " created_date " ] ,
2015-06-30 16:05:58 -07:00
}
2024-04-24 09:43:56 -04:00
2020-06-30 20:50:30 -04:00
def __str__ ( self ) :
2024-04-24 09:43:56 -04:00
return " %s gifted %s on %s : %s (redeemed %s times) " % (
self . gifting_user_id ,
self . receiving_user_id ,
self . created_date ,
self . gift_code ,
self . redeemed ,
)
2015-06-30 16:05:58 -07:00
@property
def redeemed ( self ) :
redeemed_code = MRedeemedCode . objects . filter ( gift_code = self . gift_code )
return len ( redeemed_code )
2024-04-24 09:43:56 -04:00
2015-06-30 16:05:58 -07:00
@staticmethod
def create_code ( gift_code = None ) :
2020-06-17 00:17:32 -04:00
u = str ( uuid . uuid4 ( ) )
2015-06-30 16:05:58 -07:00
code = u [ : 8 ] + u [ 9 : 13 ]
if gift_code :
2024-04-24 09:43:56 -04:00
code = gift_code + code [ len ( gift_code ) : ]
2015-06-30 16:05:58 -07:00
return code
2024-04-24 09:43:56 -04:00
2015-06-30 16:05:58 -07:00
@classmethod
2015-06-30 18:17:20 -07:00
def add ( cls , gift_code = None , duration = 0 , gifting_user_id = None , receiving_user_id = None , payment = 0 ) :
2024-04-24 09:43:56 -04:00
return cls . objects . create (
gift_code = cls . create_code ( gift_code ) ,
gifting_user_id = gifting_user_id ,
receiving_user_id = receiving_user_id ,
duration_days = duration ,
payment_amount = payment ,
)
2015-06-30 16:05:58 -07:00
2014-11-06 14:55:27 -08:00
class MRedeemedCode ( mongo . Document ) :
user_id = mongo . IntField ( )
gift_code = mongo . StringField ( )
redeemed_date = mongo . DateTimeField ( default = datetime . datetime . now )
2024-04-24 09:43:56 -04:00
2014-11-06 14:55:27 -08:00
meta = {
2024-04-24 09:43:56 -04:00
" collection " : " redeemed_codes " ,
" allow_inheritance " : False ,
" indexes " : [ " user_id " , " gift_code " , " redeemed_date " ] ,
2014-11-06 14:55:27 -08:00
}
2024-04-24 09:43:56 -04:00
2020-06-30 20:50:30 -04:00
def __str__ ( self ) :
2014-11-06 14:55:27 -08:00
return " %s redeemed %s on %s " % ( self . user_id , self . gift_code , self . redeemed_date )
2024-04-24 09:43:56 -04:00
2014-11-06 14:55:27 -08:00
@classmethod
def record ( cls , user_id , gift_code ) :
2024-04-24 09:43:56 -04:00
cls . objects . create ( user_id = user_id , gift_code = gift_code )
2015-06-30 16:05:58 -07:00
@classmethod
def redeem ( cls , user , gift_code ) :
newsblur_gift_code = MGiftCode . objects . filter ( gift_code__iexact = gift_code )
if newsblur_gift_code :
newsblur_gift_code = newsblur_gift_code [ 0 ]
2024-04-24 09:43:56 -04:00
PaymentHistory . objects . create (
user = user ,
payment_date = datetime . datetime . now ( ) ,
payment_amount = newsblur_gift_code . payment_amount ,
payment_provider = " newsblur-gift " ,
)
2015-06-30 16:05:58 -07:00
else :
# Thinkup / Good Web Bundle
2024-04-24 09:43:56 -04:00
PaymentHistory . objects . create (
user = user ,
payment_date = datetime . datetime . now ( ) ,
payment_amount = 12 ,
payment_provider = " good-web-bundle " ,
)
2015-06-30 16:05:58 -07:00
cls . record ( user . pk , gift_code )
user . profile . activate_premium ( )
logging . user ( user , " ~FG~BBRedeeming gift code: %s ~FW " % gift_code )
2024-04-24 09:43:56 -04:00
2013-05-13 16:17:49 -07:00
2017-05-18 16:59:35 -07:00
class MCustomStyling ( mongo . Document ) :
user_id = mongo . IntField ( unique = True )
custom_css = mongo . StringField ( )
custom_js = mongo . StringField ( )
updated_date = mongo . DateTimeField ( default = datetime . datetime . now )
2024-04-24 09:43:56 -04:00
2017-05-18 16:59:35 -07:00
meta = {
2024-04-24 09:43:56 -04:00
" collection " : " custom_styling " ,
" allow_inheritance " : False ,
" indexes " : [ " user_id " ] ,
2017-05-18 16:59:35 -07:00
}
2024-04-24 09:43:56 -04:00
2020-06-30 20:50:30 -04:00
def __str__ ( self ) :
2024-04-24 09:43:56 -04:00
return " %s custom style %s / %s %s " % (
self . user_id ,
len ( self . custom_css ) if self . custom_css else " - " ,
len ( self . custom_js ) if self . custom_js else " - " ,
self . updated_date ,
)
2017-05-18 16:59:35 -07:00
def canonical ( self ) :
return {
2024-04-24 09:43:56 -04:00
" css " : self . custom_css ,
" js " : self . custom_js ,
2017-05-18 16:59:35 -07:00
}
2024-04-24 09:43:56 -04:00
2017-05-18 16:59:35 -07:00
@classmethod
def get_user ( cls , user_id ) :
try :
styling = cls . objects . get ( user_id = user_id )
except cls . DoesNotExist :
return None
2024-04-24 09:43:56 -04:00
2017-05-18 16:59:35 -07:00
return styling
2024-04-24 09:43:56 -04:00
2017-05-18 16:59:35 -07:00
@classmethod
def save_user ( cls , user_id , css , js ) :
styling = cls . get_user ( user_id )
if not css and not js :
if styling :
styling . delete ( )
return
if not styling :
styling = cls . objects . create ( user_id = user_id )
styling . custom_css = css
styling . custom_js = js
styling . save ( )
2020-12-09 18:20:55 -05:00
2020-12-10 18:33:43 -05:00
class MDashboardRiver ( mongo . Document ) :
2021-04-07 15:32:11 -04:00
user_id = mongo . IntField ( unique_with = ( ) )
2020-12-10 18:33:43 -05:00
river_id = mongo . StringField ( )
river_side = mongo . StringField ( )
river_order = mongo . IntField ( )
meta = {
2024-04-24 09:43:56 -04:00
" collection " : " dashboard_river " ,
" allow_inheritance " : False ,
" indexes " : [
" user_id " ,
{
" fields " : [ " user_id " , " river_id " , " river_side " , " river_order " ] ,
" unique " : True ,
} ,
] ,
" ordering " : [ " river_order " ] ,
2020-12-10 18:33:43 -05:00
}
2020-12-09 18:20:55 -05:00
2021-01-13 15:40:31 -05:00
def __str__ ( self ) :
2021-02-05 17:18:29 -05:00
try :
u = User . objects . get ( pk = self . user_id )
except User . DoesNotExist :
u = " <missing user> "
2021-01-13 15:40:31 -05:00
return f " { u } ( { self . river_side } / { self . river_order } ): { self . river_id } "
2024-04-24 09:43:56 -04:00
2020-12-09 18:20:55 -05:00
def canonical ( self ) :
return {
2024-04-24 09:43:56 -04:00
" river_id " : self . river_id ,
" river_side " : self . river_side ,
" river_order " : self . river_order ,
2020-12-09 18:20:55 -05:00
}
2024-04-24 09:43:56 -04:00
2020-12-09 18:20:55 -05:00
@classmethod
2021-03-25 20:17:13 -04:00
def get_user_rivers ( cls , user_id ) :
2021-01-13 15:40:31 -05:00
return cls . objects ( user_id = user_id )
2020-12-09 18:20:55 -05:00
2022-05-17 13:45:51 -04:00
@classmethod
def remove_river ( cls , user_id , river_side , river_order ) :
try :
river = cls . objects . get ( user_id = user_id , river_side = river_side , river_order = river_order )
except cls . DoesNotExist :
return
river . delete ( )
for r , river in enumerate ( cls . objects . filter ( user_id = user_id , river_side = river_side ) ) :
if river . river_order != r :
logging . debug ( f " ---> Rebalancing { river } from { river . river_order } to { r } " )
river . river_order = r
river . save ( )
2020-12-09 18:20:55 -05:00
@classmethod
2020-12-10 18:33:43 -05:00
def save_user ( cls , user_id , river_id , river_side , river_order ) :
2021-04-07 15:32:11 -04:00
try :
river = cls . objects . get ( user_id = user_id , river_side = river_side , river_order = river_order )
except cls . DoesNotExist :
river = None
2022-05-17 13:45:51 -04:00
2020-12-10 18:33:43 -05:00
if not river :
2024-04-24 09:43:56 -04:00
river = cls . objects . create (
user_id = user_id , river_id = river_id , river_side = river_side , river_order = river_order
)
2020-12-09 18:20:55 -05:00
2021-01-13 15:40:31 -05:00
river . river_id = river_id
2020-12-10 18:33:43 -05:00
river . river_side = river_side
river . river_order = river_order
river . save ( )
2020-12-09 18:20:55 -05:00
2024-04-24 09:43:56 -04:00
2013-05-13 16:17:49 -07:00
class RNewUserQueue :
KEY = " new_user_queue "
2024-04-24 09:43:56 -04:00
2013-05-13 18:03:17 -07:00
@classmethod
def activate_next ( cls ) :
count = cls . user_count ( )
if not count :
return
2024-04-24 09:43:56 -04:00
2013-05-13 18:03:17 -07:00
user_id = cls . pop_user ( )
2014-03-13 16:47:31 -07:00
try :
user = User . objects . get ( pk = user_id )
2015-03-09 15:32:05 -07:00
except User . DoesNotExist :
2024-04-24 09:43:56 -04:00
logging . debug (
" ~FRCan ' t activate free account, can ' t find user ~SB %s ~SN. ~FB %s still in queue. "
% ( user_id , count - 1 )
)
2014-03-13 16:47:31 -07:00
return
2024-04-24 09:43:56 -04:00
logging . user (
user ,
" ~FBActivating free account ( %s / %s ). %s still in queue. "
% ( user . email , user . profile . last_seen_ip , ( count - 1 ) ) ,
)
2013-05-13 18:03:17 -07:00
user . profile . activate_free ( )
2024-04-24 09:43:56 -04:00
2015-06-22 11:03:57 -07:00
@classmethod
def activate_all ( cls ) :
count = cls . user_count ( )
if not count :
logging . debug ( " ~FBNo users to activate, sleeping... " )
return
2024-04-24 09:43:56 -04:00
2015-06-22 11:03:57 -07:00
for i in range ( count ) :
cls . activate_next ( )
2024-04-24 09:43:56 -04:00
2013-05-13 16:17:49 -07:00
@classmethod
def add_user ( cls , user_id ) :
2015-07-27 18:35:25 -07:00
r = redis . Redis ( connection_pool = settings . REDIS_FEED_UPDATE_POOL )
2013-05-13 16:17:49 -07:00
now = time . time ( )
2024-04-24 09:43:56 -04:00
r . zadd ( cls . KEY , { user_id : now } )
2013-05-13 16:17:49 -07:00
@classmethod
def user_count ( cls ) :
2015-07-27 18:35:25 -07:00
r = redis . Redis ( connection_pool = settings . REDIS_FEED_UPDATE_POOL )
2013-05-13 16:17:49 -07:00
count = r . zcard ( cls . KEY )
return count
2024-04-24 09:43:56 -04:00
2013-05-13 16:17:49 -07:00
@classmethod
def user_position ( cls , user_id ) :
2015-07-27 18:35:25 -07:00
r = redis . Redis ( connection_pool = settings . REDIS_FEED_UPDATE_POOL )
2013-05-13 18:03:17 -07:00
position = r . zrank ( cls . KEY , user_id )
2021-03-25 16:28:50 -04:00
if position is None :
2021-03-25 16:29:42 -04:00
return - 1
2013-05-13 18:03:17 -07:00
if position > = 0 :
return position + 1
2024-04-24 09:43:56 -04:00
2013-05-13 16:17:49 -07:00
@classmethod
2013-05-13 18:03:17 -07:00
def pop_user ( cls ) :
2015-07-27 18:35:25 -07:00
r = redis . Redis ( connection_pool = settings . REDIS_FEED_UPDATE_POOL )
2013-05-13 18:03:17 -07:00
user = r . zrange ( cls . KEY , 0 , 0 ) [ 0 ]
2013-05-13 16:17:49 -07:00
r . zrem ( cls . KEY , user )
2013-05-13 18:03:17 -07:00
2013-05-13 16:17:49 -07:00
return user