mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-27 03:00:12 -04:00
promote: Stop using VDate for advance date checking.
The logic was getting too complicated so has been moved into promote.get_date_limits().
This commit is contained in:
@@ -269,8 +269,8 @@ class SponsorController(PromoteController):
|
||||
|
||||
@validate(
|
||||
VSponsorAdmin(),
|
||||
start=VDate('startdate', reference_date=promote.promo_datetime_now),
|
||||
end=VDate('enddate', reference_date=promote.promo_datetime_now),
|
||||
start=VDate('startdate'),
|
||||
end=VDate('enddate'),
|
||||
sr_name=nop('sr_name'),
|
||||
collection_name=nop('collection_name'),
|
||||
)
|
||||
@@ -917,8 +917,8 @@ class PromoteApiController(ApiController):
|
||||
@validatedForm(
|
||||
VSponsorAdmin(),
|
||||
VModhash(),
|
||||
start=VDate('startdate', reference_date=promote.promo_datetime_now),
|
||||
end=VDate('enddate', reference_date=promote.promo_datetime_now),
|
||||
start=VDate('startdate'),
|
||||
end=VDate('enddate'),
|
||||
sr=VSubmitSR('sr', promotion=True),
|
||||
)
|
||||
def POST_add_roadblock(self, form, jquery, start, end, sr):
|
||||
@@ -942,8 +942,8 @@ class PromoteApiController(ApiController):
|
||||
@validatedForm(
|
||||
VSponsorAdmin(),
|
||||
VModhash(),
|
||||
start=VDate('startdate', reference_date=promote.promo_datetime_now),
|
||||
end=VDate('enddate', reference_date=promote.promo_datetime_now),
|
||||
start=VDate('startdate'),
|
||||
end=VDate('enddate'),
|
||||
sr=VSubmitSR('sr', promotion=True),
|
||||
)
|
||||
def POST_rm_roadblock(self, form, jquery, start, end, sr):
|
||||
@@ -959,21 +959,8 @@ class PromoteApiController(ApiController):
|
||||
@validatedForm(
|
||||
VSponsor('link_id36'),
|
||||
VModhash(),
|
||||
start=VDate(
|
||||
'startdate',
|
||||
earliest=timedelta(days=g.min_promote_future),
|
||||
latest=timedelta(days=g.max_promote_future),
|
||||
reference_date=promote.promo_datetime_now,
|
||||
business_days=True,
|
||||
sponsor_override=True,
|
||||
),
|
||||
end=VDate(
|
||||
'enddate',
|
||||
earliest=timedelta(days=g.min_promote_future),
|
||||
latest=timedelta(days=g.max_promote_future),
|
||||
reference_date=promote.promo_datetime_now,
|
||||
sponsor_override=True,
|
||||
),
|
||||
start=VDate('startdate'),
|
||||
end=VDate('enddate'),
|
||||
link=VLink('link_id36'),
|
||||
bid=VFloat('bid', coerce=False),
|
||||
target=VPromoTarget(),
|
||||
@@ -1000,10 +987,31 @@ class PromoteApiController(ApiController):
|
||||
|
||||
cpm = PromotionPrices.get_price(c.user, target, location)
|
||||
|
||||
if (form.has_errors('startdate', errors.BAD_DATE,
|
||||
errors.DATE_TOO_EARLY, errors.DATE_TOO_LATE) or
|
||||
form.has_errors('enddate', errors.BAD_DATE, errors.DATE_TOO_EARLY,
|
||||
errors.DATE_TOO_LATE, errors.BAD_DATE_RANGE)):
|
||||
if (form.has_errors('startdate', errors.BAD_DATE) or
|
||||
form.has_errors('enddate', errors.BAD_DATE)):
|
||||
return
|
||||
|
||||
min_start, max_start, max_end = promote.get_date_limits(
|
||||
link, c.user_is_sponsor)
|
||||
if start.date() < min_start:
|
||||
c.errors.add(errors.DATE_TOO_EARLY,
|
||||
msg_params={'day': min_start.strftime("%m/%d/%Y")},
|
||||
field='startdate')
|
||||
form.has_errors('startdate', errors.DATE_TOO_EARLY)
|
||||
return
|
||||
|
||||
if start.date() > max_start:
|
||||
c.errors.add(errors.DATE_TOO_LATE,
|
||||
msg_params={'day': max_start.strftime("%m/%d/%Y")},
|
||||
field='startdate')
|
||||
form.has_errors('startdate', errors.DATE_TOO_LATE)
|
||||
return
|
||||
|
||||
if end.date() > max_end:
|
||||
c.errors.add(errors.DATE_TOO_LATE,
|
||||
msg_params={'day': max_end.strftime("%m/%d/%Y")},
|
||||
field='enddate')
|
||||
form.has_errors('enddate', errors.DATE_TOO_LATE)
|
||||
return
|
||||
|
||||
if end < start:
|
||||
@@ -1011,16 +1019,6 @@ class PromoteApiController(ApiController):
|
||||
form.has_errors('enddate', errors.BAD_DATE_RANGE)
|
||||
return
|
||||
|
||||
# check that start is not so late that authorization hold will expire
|
||||
if not c.user_is_sponsor:
|
||||
max_start = promote.get_max_startdate()
|
||||
if start > max_start:
|
||||
c.errors.add(errors.DATE_TOO_LATE,
|
||||
msg_params={'day': max_start.strftime("%m/%d/%Y")},
|
||||
field='startdate')
|
||||
form.has_errors('startdate', errors.DATE_TOO_LATE)
|
||||
return
|
||||
|
||||
# Limit the number of PromoCampaigns a Link can have
|
||||
# Note that the front end should prevent the user from getting
|
||||
# this far
|
||||
@@ -1148,20 +1146,19 @@ class PromoteApiController(ApiController):
|
||||
if campaign_has_oversold_error(form, campaign):
|
||||
return
|
||||
|
||||
# check that start is not so late that authorization hold will expire
|
||||
max_start = promote.get_max_startdate()
|
||||
if campaign.start_date > max_start:
|
||||
# check the campaign dates are still valid (user may have created
|
||||
# the campaign a few days ago)
|
||||
min_start, max_start, max_end = promote.get_date_limits(
|
||||
link, c.user_is_sponsor)
|
||||
|
||||
if campaign.start_date.date() > max_start:
|
||||
msg = _("please change campaign start date to %(date)s or earlier")
|
||||
date = format_date(max_start, format="short", locale=c.locale)
|
||||
msg %= {'date': date}
|
||||
form.set_text(".status", msg)
|
||||
return
|
||||
|
||||
# check the campaign start date is still valid (user may have created
|
||||
# the campaign a few days ago)
|
||||
now = promote.promo_datetime_now()
|
||||
min_start = now + timedelta(days=g.min_promote_future)
|
||||
if campaign.start_date.date() < min_start.date():
|
||||
if campaign.start_date.date() < min_start:
|
||||
msg = _("please change campaign start date to %(date)s or later")
|
||||
date = format_date(min_start, format="short", locale=c.locale)
|
||||
msg %= {'date': date}
|
||||
|
||||
@@ -117,7 +117,7 @@ from r2.lib.menus import OffsiteButton, menu, JsNavMenu
|
||||
from r2.lib.normalized_hot import normalized_hot
|
||||
from r2.lib.strings import plurals, rand_strings, strings, Score
|
||||
from r2.lib.utils import is_subdomain, title_to_url, query_string, UrlParser
|
||||
from r2.lib.utils import url_links_builder, make_offset_date, median, to36
|
||||
from r2.lib.utils import url_links_builder, median, to36
|
||||
from r2.lib.utils import trunc_time, timesince, timeuntil, weighted_lottery
|
||||
from r2.lib.template_helpers import (
|
||||
add_sr,
|
||||
@@ -144,7 +144,6 @@ import csv
|
||||
import hmac
|
||||
import hashlib
|
||||
import cStringIO
|
||||
import pytz
|
||||
import sys, random, datetime, calendar, simplejson, re, time
|
||||
import time
|
||||
from itertools import chain, product
|
||||
@@ -3868,26 +3867,8 @@ class PromoteLinkEdit(PromoteLinkBase):
|
||||
)
|
||||
self.bids.append(row)
|
||||
|
||||
# determine date range
|
||||
now = promote.promo_datetime_now()
|
||||
|
||||
if c.user_is_sponsor:
|
||||
min_start = now
|
||||
elif promote.is_accepted(link):
|
||||
min_start = make_offset_date(now, 1, business_days=True)
|
||||
else:
|
||||
min_start = make_offset_date(now, g.min_promote_future,
|
||||
business_days=True)
|
||||
|
||||
if c.user_is_sponsor:
|
||||
max_end = now + datetime.timedelta(days=366)
|
||||
else:
|
||||
max_end = now + datetime.timedelta(days=g.max_promote_future)
|
||||
|
||||
if c.user_is_sponsor:
|
||||
max_start = max_end - datetime.timedelta(days=1)
|
||||
else:
|
||||
max_start = promote.get_max_startdate()
|
||||
min_start, max_start, max_end = promote.get_date_limits(
|
||||
link, c.user_is_sponsor)
|
||||
|
||||
default_end = min_start + datetime.timedelta(days=2)
|
||||
default_start = min_start
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
# Inc. All Rights Reserved.
|
||||
###############################################################################
|
||||
|
||||
import calendar
|
||||
from collections import namedtuple
|
||||
from datetime import datetime, timedelta
|
||||
import datetime
|
||||
from decimal import Decimal, ROUND_DOWN, ROUND_UP
|
||||
import hashlib
|
||||
import hmac
|
||||
@@ -34,6 +35,7 @@ import urlparse
|
||||
|
||||
from pylons import g, c
|
||||
from pylons.i18n import ungettext
|
||||
from pytz import timezone
|
||||
|
||||
from r2.lib import (
|
||||
authorize,
|
||||
@@ -445,19 +447,65 @@ def auth_campaign(link, campaign, user, pay_id):
|
||||
# midnight eastern-US.
|
||||
# TODO: make this a config parameter
|
||||
timezone_offset = -5 # hours
|
||||
timezone_offset = timedelta(0, timezone_offset * 3600)
|
||||
timezone_offset = datetime.timedelta(0, timezone_offset * 3600)
|
||||
def promo_datetime_now(offset=None):
|
||||
now = datetime.now(g.tz) + timezone_offset
|
||||
now = datetime.datetime.now(g.tz) + timezone_offset
|
||||
if offset is not None:
|
||||
now += timedelta(offset)
|
||||
now += datetime.timedelta(offset)
|
||||
return now
|
||||
|
||||
|
||||
def get_max_startdate():
|
||||
# authorization hold happens now but expires after 30 days. charge
|
||||
# happens 1 day before the campaign launches. the latest a campaign
|
||||
# can start is 30 days from now (it will get charged in 29 days).
|
||||
return promo_datetime_now() + timedelta(days=30)
|
||||
# campaigns can launch the following day if they're created before 17:00 PDT
|
||||
DAILY_CUTOFF = datetime.time(17, tzinfo=timezone("US/Pacific"))
|
||||
|
||||
def get_date_limits(link, is_sponsor=False):
|
||||
promo_today = promo_datetime_now().date()
|
||||
|
||||
if is_sponsor:
|
||||
min_start = promo_today
|
||||
elif is_accepted(link):
|
||||
# link is already accepted--let user create a campaign starting
|
||||
# tomorrow because it doesn't need to be re-reviewed
|
||||
min_start = promo_today + datetime.timedelta(days=1)
|
||||
else:
|
||||
# campaign and link will need to be reviewed before they can launch.
|
||||
# review can happen until DAILY_CUTOFF PDT Monday through Friday and
|
||||
# Sunday. Any campaign created after DAILY_CUTOFF is treated as if it
|
||||
# were created the following day.
|
||||
now = datetime.datetime.now(tz=timezone("US/Pacific"))
|
||||
now_today = now.date()
|
||||
too_late_for_review = now.time() > DAILY_CUTOFF
|
||||
|
||||
if too_late_for_review and now_today.weekday() == calendar.FRIDAY:
|
||||
# no review late on Friday--earliest review is Sunday to launch
|
||||
# on Monday
|
||||
min_start = now_today + datetime.timedelta(days=3)
|
||||
elif now_today.weekday() == calendar.SATURDAY:
|
||||
# no review any time on Saturday--earliest review is Sunday to
|
||||
# launch on Monday
|
||||
min_start = now_today + datetime.timedelta(days=2)
|
||||
elif too_late_for_review:
|
||||
# no review late in the day--earliest review is tomorrow to
|
||||
# launch the following day
|
||||
min_start = now_today + datetime.timedelta(days=2)
|
||||
else:
|
||||
# review will happen today so can launch tomorrow
|
||||
min_start = now_today + datetime.timedelta(days=1)
|
||||
|
||||
if is_sponsor:
|
||||
max_end = promo_today + datetime.timedelta(days=366)
|
||||
else:
|
||||
max_end = promo_today + datetime.timedelta(days=93)
|
||||
|
||||
if is_sponsor:
|
||||
max_start = max_end - datetime.timedelta(days=1)
|
||||
else:
|
||||
# authorization hold happens now but expires after 30 days. charge
|
||||
# happens 1 day before the campaign launches. the latest a campaign
|
||||
# can start is 30 days from now (it will get charged in 29 days).
|
||||
max_start = promo_today + datetime.timedelta(days=30)
|
||||
|
||||
return min_start, max_start, max_end
|
||||
|
||||
|
||||
def accept_promotion(link):
|
||||
@@ -693,8 +741,8 @@ def make_daily_promotions():
|
||||
|
||||
def finalize_completed_campaigns(daysago=1):
|
||||
# PromoCampaign.end_date is utc datetime with year, month, day only
|
||||
now = datetime.now(g.tz)
|
||||
date = now - timedelta(days=daysago)
|
||||
now = datetime.datetime.now(g.tz)
|
||||
date = now - datetime.timedelta(days=daysago)
|
||||
date = date.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
q = PromoCampaign._query(PromoCampaign.c.end_date == date,
|
||||
@@ -874,8 +922,8 @@ def get_total_run(thing):
|
||||
|
||||
# a manually launched promo (e.g., sr discovery) might not have campaigns.
|
||||
if not earliest or not latest:
|
||||
latest = datetime.utcnow()
|
||||
earliest = latest - timedelta(days=30) # last month
|
||||
latest = datetime.datetime.utcnow()
|
||||
earliest = latest - datetime.timedelta(days=30) # last month
|
||||
|
||||
# ugh this stuff is a mess. they're stored as "UTC" but actually mean UTC-5.
|
||||
earliest = earliest.replace(tzinfo=g.tz) - timezone_offset
|
||||
@@ -886,7 +934,7 @@ def get_total_run(thing):
|
||||
|
||||
def get_traffic_dates(thing):
|
||||
"""Retrieve the start and end of a Promoted Link or PromoCampaign."""
|
||||
now = datetime.now(g.tz).replace(minute=0, second=0, microsecond=0)
|
||||
now = datetime.datetime.now(g.tz).replace(minute=0, second=0, microsecond=0)
|
||||
start, end = get_total_run(thing)
|
||||
end = min(now, end)
|
||||
return start, end
|
||||
@@ -894,7 +942,7 @@ def get_traffic_dates(thing):
|
||||
|
||||
def get_billable_impressions(campaign):
|
||||
start, end = get_traffic_dates(campaign)
|
||||
if start > datetime.now(g.tz):
|
||||
if start > datetime.datetime.now(g.tz):
|
||||
return 0
|
||||
|
||||
traffic_lookup = traffic.TargetedImpressionsByCodename.promotion_history
|
||||
@@ -966,9 +1014,9 @@ def Run(verbose=True):
|
||||
"""
|
||||
|
||||
if verbose:
|
||||
print "%s promote.py:Run() - make_daily_promotions()" % datetime.now(g.tz)
|
||||
print "%s promote.py:Run() - make_daily_promotions()" % datetime.datetime.now(g.tz)
|
||||
|
||||
make_daily_promotions()
|
||||
|
||||
if verbose:
|
||||
print "%s promote.py:Run() - finished" % datetime.now(g.tz)
|
||||
print "%s promote.py:Run() - finished" % datetime.datetime.now(g.tz)
|
||||
|
||||
@@ -41,7 +41,7 @@ and choose "frontpage" or "targeted" and click "save":
|
||||
|
||||
Please note that we can't approve your ad until you have authorized your credit
|
||||
card payment, and that your ad must be approved before it goes live on your
|
||||
selected dates. We require ${g.min_promote_future} ${ungettext("business day", "business days", g.min_promote_future)} as a grace period for the approval
|
||||
selected dates. We require one business day as a grace period for the approval
|
||||
process before the ad can go live. To pay for your campaign, click the "pay"
|
||||
button within the campaign dashboard on the link above.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user