243 lines
8.3 KiB
Python
243 lines
8.3 KiB
Python
"""
|
|
external library imports
|
|
"""
|
|
import logging
|
|
|
|
from celery.task import task
|
|
from datetime import timedelta
|
|
from time import sleep
|
|
|
|
"""
|
|
django imports
|
|
"""
|
|
from django.conf import settings
|
|
from django.contrib.auth.models import User
|
|
from django.core.mail import send_mail
|
|
from django.core.management import call_command
|
|
from django.utils.timezone import now
|
|
from notification.engine import send_all
|
|
from notification import models as notification
|
|
|
|
from mailchimp3 import MailChimp
|
|
from mailchimp3.mailchimpclient import MailChimpError
|
|
|
|
|
|
"""
|
|
regluit imports
|
|
"""
|
|
from regluit.core import (
|
|
bookloader,
|
|
models,
|
|
goodreads,
|
|
librarything,
|
|
mobigen
|
|
)
|
|
from regluit.core.models import Acq, Campaign, EbookFile, Gift, UserProfile
|
|
from regluit.core.signals import deadline_impending
|
|
from regluit.core.parameters import RESERVE, REWARDS, THANKS
|
|
from regluit.utils.localdatetime import date_today
|
|
|
|
logger = logging.getLogger(__name__)
|
|
mc_client = MailChimp(mc_api=settings.MAILCHIMP_API_KEY)
|
|
|
|
@task
|
|
def populate_edition(isbn):
|
|
"""given an edition this task will populate the database with additional
|
|
information about related editions and subjects related to this edition
|
|
"""
|
|
bookloader.add_related(isbn)
|
|
edition=models.Edition.get_by_isbn(isbn)
|
|
if edition:
|
|
bookloader.add_openlibrary(edition.work)
|
|
return edition
|
|
|
|
@task
|
|
def load_goodreads_shelf_into_wishlist(user_id, shelf_name='all', goodreads_user_id=None, max_books=None,
|
|
expected_number_of_books=None):
|
|
user=User.objects.get(id=user_id)
|
|
return goodreads.load_goodreads_shelf_into_wishlist(user,shelf_name,goodreads_user_id,max_books, expected_number_of_books)
|
|
|
|
@task
|
|
def load_librarything_into_wishlist(user_id, lt_username, max_books=None):
|
|
user=User.objects.get(id=user_id)
|
|
return librarything.load_librarything_into_wishlist(user, lt_username, max_books)
|
|
|
|
@task
|
|
def fac(n, sleep_interval=None):
|
|
# used to test celery task execution
|
|
if not(isinstance(n,int) and n >= 0):
|
|
raise Exception("You can't calculate a factorial of %s " % (str(n)))
|
|
if n <= 1:
|
|
return 1
|
|
else:
|
|
res = 1
|
|
for i in range(2,n+1):
|
|
res = res*i
|
|
fac.update_state(state="PROGRESS", meta={"current": i, "total": n})
|
|
if sleep_interval is not None:
|
|
sleep(sleep_interval)
|
|
return res
|
|
|
|
|
|
@task
|
|
def send_mail_task(subject, message, from_email, recipient_list,
|
|
fail_silently=False, auth_user=None, auth_password=None,
|
|
connection=None, override_from_email=True):
|
|
"""a task to drop django.core.mail.send_mail into """
|
|
# NOTE: since we are currently using Amazon SES, which allows email to be sent only from validated email
|
|
# addresses, we force from_email to be one of the validated address unless override_from_email is FALSE
|
|
try:
|
|
if override_from_email:
|
|
try:
|
|
from_email = settings.DEFAULT_FROM_EMAIL
|
|
except:
|
|
pass
|
|
r = send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=auth_user,
|
|
auth_password=auth_password, connection=connection)
|
|
logger.info('sent mail about %s to %s' % (subject, recipient_list))
|
|
except:
|
|
r = logger.info('failed to send message:' + message)
|
|
return r
|
|
|
|
#task to update the status of active campaigns
|
|
@task
|
|
def update_active_campaign_status():
|
|
"""update the status of all active campaigns -- presumed to be run at midnight Eastern time"""
|
|
return [c.update_status(send_notice=True, ignore_deadline_for_success=True, process_transactions=True) for c in Campaign.objects.filter(status='Active') ]
|
|
|
|
@task
|
|
def emit_notifications():
|
|
logger.info('notifications emitting' )
|
|
return send_all()
|
|
|
|
@task
|
|
def report_new_ebooks(created=None): #created= creation date
|
|
if created:
|
|
period = (created, created+timedelta(days=1))
|
|
else:
|
|
period = (date_today()-timedelta(days=1), date_today())
|
|
works = models.Work.objects.filter(editions__ebooks__created__range=period).distinct()
|
|
for work in works:
|
|
# only notify if a new ebooks are active, don't notify person if the book was just wished
|
|
# ebooks() only returns active ebooks
|
|
for ebook in work.ebooks().filter(created__range=period):
|
|
notification.send_now(
|
|
work.wished_by(excluding=period),
|
|
"wishlist_unglued_book_released",
|
|
{'work':work},
|
|
True
|
|
)
|
|
break
|
|
|
|
@task
|
|
def notify_ending_soon():
|
|
c_active = Campaign.objects.filter(status='Active', type=REWARDS)
|
|
for c in c_active:
|
|
if c.deadline - now() < timedelta(7) and c.deadline - now() >= timedelta(6):
|
|
"""
|
|
if the campaign is still active and there's only a week left until it closes, send reminder notification
|
|
"""
|
|
deadline_impending.send(sender=None, campaign=c)
|
|
|
|
@task
|
|
def watermark_acq(acq_id):
|
|
try:
|
|
acq = Acq.objects.get(acq_id)
|
|
except Acq.DoesNotExist as e:
|
|
logger.error("error getting acq %s" % (acq_id))
|
|
return False
|
|
acq.get_watermarked()
|
|
|
|
@task
|
|
def process_ebfs(campaign_id):
|
|
try:
|
|
campaign = Campaign.objects.get(campaign_id)
|
|
except Campaign.DoesNotExist as e:
|
|
logger.error("error getting acq %s" % (campaign_id))
|
|
return False
|
|
if campaign.type == THANKS:
|
|
if campaign.use_add_ask:
|
|
campaign.add_ask_to_ebfs()
|
|
else:
|
|
campaign.revert_asks()
|
|
campaign.make_mobis()
|
|
|
|
|
|
@task
|
|
def make_mobi(ebookfile_id):
|
|
try:
|
|
ebookfile = EbookFile.objects.get(ebookfile_id)
|
|
except EbookFile.DoesNotExist as e:
|
|
logger.error("error getting EbookFile %s" % (ebookfile_id))
|
|
return False
|
|
return ebookfile.make_mobi()
|
|
|
|
@task
|
|
def refresh_acqs():
|
|
in_10_min = now() + timedelta(minutes=10)
|
|
acqs = Acq.objects.filter(refreshed=False, refreshes__lt=in_10_min)
|
|
logger.info('refreshing %s acqs' % acqs.count())
|
|
for acq in acqs:
|
|
for hold in acq.holds:
|
|
# create a 1 day reserve on the acq
|
|
reserve_acq = Acq.objects.create(
|
|
user = hold.user,
|
|
work = hold.work,
|
|
license = RESERVE,
|
|
lib_acq = acq,
|
|
)
|
|
# the post_save handler takes care of pushing expires vis acq.expires_in
|
|
|
|
# notify the user with the hold
|
|
if 'example.org' not in reserve_acq.user.email:
|
|
notification.send_now([reserve_acq.user], "library_reserve", {'acq':reserve_acq})
|
|
# delete the hold
|
|
hold.delete()
|
|
break
|
|
else:
|
|
acq.refreshed = True
|
|
|
|
@task
|
|
def convert_to_mobi(input_url, input_format="application/epub+zip"):
|
|
return mobigen.convert_to_mobi(input_url, input_format)
|
|
|
|
@task
|
|
def ml_subscribe_task(profile_id, **kwargs):
|
|
try:
|
|
profile = UserProfile.objects.get(profile_id)
|
|
except UserProfile.DoesNotExist as e:
|
|
logger.error("error getting profile %s" % (profile_id))
|
|
return False
|
|
|
|
try:
|
|
if not profile.on_ml:
|
|
data = {"email_address": profile.user.email, "status_if_new": "pending"}
|
|
mc_client.lists.members.create_or_update(
|
|
list_id=settings.MAILCHIMP_NEWS_ID,
|
|
subscriber_hash=profile.user.email,
|
|
data=data,
|
|
)
|
|
return True
|
|
except Exception as e:
|
|
logger.error("error subscribing to mailchimp list %s" % (e))
|
|
return False
|
|
|
|
@task
|
|
def notify_unclaimed_gifts():
|
|
unclaimed = Gift.objects.filter(used=None)
|
|
for gift in unclaimed:
|
|
"""
|
|
send notice every 7 days, but stop at 10x
|
|
"""
|
|
unclaimed_duration = (now() - gift.acq.created ).days
|
|
if unclaimed_duration > 70:
|
|
return
|
|
if unclaimed_duration > 0 and unclaimed_duration % 7 == 0 : # first notice in 7 days
|
|
notification.send_now([gift.acq.user], "purchase_gift_waiting", {'gift':gift}, True)
|
|
notification.send_now([gift.giver], "purchase_notgot_gift", {'gift':gift}, True)
|
|
|
|
@task
|
|
def periodic_cleanup():
|
|
call_command('clearsessions')
|
|
call_command('cleanupregistration')
|