mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-01-29 00:38:11 -05:00
Split up the spotlight.
This commit is contained in:
@@ -41,7 +41,6 @@ import r2.lib.search as search
|
||||
from r2.lib.template_helpers import add_sr
|
||||
from r2.lib.utils import iters, check_cheating, timeago
|
||||
from r2.lib import sup
|
||||
from r2.lib.promote import randomized_promotion_list
|
||||
from r2.lib.validator import *
|
||||
import socket
|
||||
|
||||
@@ -224,13 +223,40 @@ class HotController(FixListing, ListingController):
|
||||
where = 'hot'
|
||||
extra_page_classes = ListingController.extra_page_classes + ['hot-page']
|
||||
|
||||
def spotlight(self):
|
||||
"""Build the Spotlight or a single promoted link.
|
||||
def make_requested_ad(self):
|
||||
try:
|
||||
link = Link._by_fullname(self.requested_ad, data=True)
|
||||
except NotFound:
|
||||
self.abort404()
|
||||
|
||||
if not (link.promoted and
|
||||
(c.user_is_sponsor or
|
||||
c.user_is_loggedin and link.author_id == c.user._id)):
|
||||
self.abort403()
|
||||
|
||||
if not promote.is_live_on_sr(link, c.site.name):
|
||||
self.abort403()
|
||||
|
||||
res = wrap_links([link._fullname], wrapper=self.builder_wrapper,
|
||||
skip=False)
|
||||
if res.things:
|
||||
return res
|
||||
|
||||
def make_single_ad(self):
|
||||
promo_tuples = promote.lottery_promoted_links(c.user, c.site, n=10)
|
||||
b = CampaignBuilder(promo_tuples, wrap=self.builder_wrapper,
|
||||
keep_fn=organic.keep_fresh_links, num=1, skip=True)
|
||||
res = LinkListing(b, nextprev=False).listing()
|
||||
if res.things:
|
||||
return res
|
||||
|
||||
def make_spotlight(self):
|
||||
"""Build the Spotlight.
|
||||
|
||||
The frontpage gets a Spotlight box that contains promoted and organic
|
||||
links from the user's subscribed subreddits and promoted links targeted
|
||||
to the frontpage. Other subreddits get a single promoted link. In either
|
||||
case if the user has disabled ads promoted links will not be shown.
|
||||
to the frontpage. If the user has disabled ads promoted links will not
|
||||
be shown.
|
||||
|
||||
The content of the Spotlight box is a bit tricky because a single
|
||||
version of the frontpage is cached and displayed to all logged out
|
||||
@@ -248,103 +274,55 @@ class HotController(FixListing, ListingController):
|
||||
|
||||
"""
|
||||
|
||||
campaigns_by_link = {}
|
||||
if (self.requested_ad or
|
||||
not isinstance(c.site, DefaultSR) and c.user.pref_show_sponsors):
|
||||
organic_fullnames = organic.organic_links(c.user)
|
||||
promoted_links = []
|
||||
|
||||
link_ids = None
|
||||
# If prefs allow it, mix in promoted links and sr discovery content
|
||||
if c.user.pref_show_sponsors or not c.user.gold:
|
||||
if g.live_config['sr_discovery_links']:
|
||||
organic_fullnames.extend(g.live_config['sr_discovery_links'])
|
||||
|
||||
if self.requested_ad:
|
||||
link = None
|
||||
try:
|
||||
link = Link._by_fullname(self.requested_ad)
|
||||
except NotFound:
|
||||
pass
|
||||
n_promoted = 100
|
||||
n_build = 10
|
||||
promo_tuples = promote.sample_promoted_links(c.user, c.site,
|
||||
n=n_promoted)
|
||||
promo_tuples = sorted(promo_tuples,
|
||||
key=lambda p: p.weight,
|
||||
reverse=True)
|
||||
promo_build = promo_tuples[:n_build]
|
||||
promo_stub = promo_tuples[n_build:]
|
||||
b = CampaignBuilder(promo_build,
|
||||
wrap=self.builder_wrapper,
|
||||
keep_fn=promote.is_promoted)
|
||||
promoted_links = b.get_items()[0]
|
||||
promoted_links.extend(promo_stub)
|
||||
|
||||
if not (link and link.promoted and
|
||||
(c.user_is_sponsor or
|
||||
c.user_is_loggedin and link.author_id == c.user._id)):
|
||||
return self.abort404()
|
||||
if not (organic_fullnames or promoted_links):
|
||||
return None
|
||||
|
||||
# check if we can show the requested ad
|
||||
if promote.is_live_on_sr(link, c.site.name):
|
||||
link_ids = [link._fullname]
|
||||
else:
|
||||
return _("requested campaign not eligible for display")
|
||||
else:
|
||||
# no organic box on a hot page, then show a random promoted link
|
||||
promo_tuples = randomized_promotion_list(c.user, c.site)
|
||||
link_ids, camp_ids = zip(*promo_tuples) if promo_tuples else ([],[])
|
||||
random.shuffle(organic_fullnames)
|
||||
organic_fullnames = organic_fullnames[:10]
|
||||
b = IDBuilder(organic_fullnames,
|
||||
wrap=self.builder_wrapper,
|
||||
keep_fn=organic.keep_fresh_links,
|
||||
skip=True)
|
||||
organic_links = b.get_items()[0]
|
||||
|
||||
# save campaign-to-link mapping so campaign can be added to
|
||||
# link data later (for tracking.) Gotcha: assumes each link
|
||||
# appears for only campaign
|
||||
campaigns_by_link = dict(promo_tuples)
|
||||
has_subscribed = c.user.has_subscribed
|
||||
interestbar_prob = g.live_config['spotlight_interest_sub_p'
|
||||
if has_subscribed else
|
||||
'spotlight_interest_nosub_p']
|
||||
interestbar = InterestBar(has_subscribed)
|
||||
promotion_prob = 0.5 if c.user_is_loggedin else 1.
|
||||
|
||||
if link_ids:
|
||||
res = wrap_links(link_ids, wrapper=self.builder_wrapper,
|
||||
num=1, keep_fn=organic.keep_fresh_links,
|
||||
skip=True)
|
||||
res.parent_name = "promoted"
|
||||
if res.things:
|
||||
# store campaign id for tracking
|
||||
for thing in res.things:
|
||||
thing.campaign = campaigns_by_link.get(thing._fullname, None)
|
||||
return res
|
||||
|
||||
elif (isinstance(c.site, DefaultSR)
|
||||
and (not c.user_is_loggedin
|
||||
or (c.user_is_loggedin and c.user.pref_organic))):
|
||||
|
||||
organic_fullnames = organic.organic_links(c.user)
|
||||
promoted_links = []
|
||||
|
||||
# If prefs allow it, mix in promoted links and sr discovery content
|
||||
if c.user.pref_show_sponsors or not c.user.gold:
|
||||
if g.live_config['sr_discovery_links']:
|
||||
organic_fullnames.extend(g.live_config['sr_discovery_links'])
|
||||
|
||||
n_promoted = 100
|
||||
n_build = 10
|
||||
promo_tuples = promote.sample_promoted_links(c.user, c.site,
|
||||
n_promoted)
|
||||
promo_tuples = sorted(promo_tuples,
|
||||
key=lambda p: p.weight,
|
||||
reverse=True)
|
||||
promo_build = promo_tuples[:n_build]
|
||||
promo_stub = promo_tuples[n_build:]
|
||||
b = CampaignBuilder(promo_build,
|
||||
wrap=self.builder_wrapper,
|
||||
keep_fn=promote.is_promoted)
|
||||
promoted_links = b.get_items()[0]
|
||||
promoted_links.extend(promo_stub)
|
||||
|
||||
if not (organic_fullnames or promoted_links):
|
||||
return None
|
||||
|
||||
random.shuffle(organic_fullnames)
|
||||
organic_fullnames = organic_fullnames[:10]
|
||||
b = IDBuilder(organic_fullnames,
|
||||
wrap = self.builder_wrapper,
|
||||
keep_fn = organic.keep_fresh_links,
|
||||
skip = True)
|
||||
organic_links = b.get_items()[0]
|
||||
|
||||
has_subscribed = c.user.has_subscribed
|
||||
interestbar_prob = g.live_config['spotlight_interest_sub_p'
|
||||
if has_subscribed else
|
||||
'spotlight_interest_nosub_p']
|
||||
interestbar = InterestBar(has_subscribed)
|
||||
promotion_prob = 0.5 if c.user_is_loggedin else 1.
|
||||
|
||||
s = SpotlightListing(organic_links=organic_links,
|
||||
promoted_links=promoted_links,
|
||||
interestbar=interestbar,
|
||||
interestbar_prob=interestbar_prob,
|
||||
promotion_prob=promotion_prob,
|
||||
max_num = self.listing_obj.max_num,
|
||||
max_score = self.listing_obj.max_score).listing()
|
||||
return s
|
||||
s = SpotlightListing(organic_links=organic_links,
|
||||
promoted_links=promoted_links,
|
||||
interestbar=interestbar,
|
||||
interestbar_prob=interestbar_prob,
|
||||
promotion_prob=promotion_prob,
|
||||
max_num = self.listing_obj.max_num,
|
||||
max_score = self.listing_obj.max_score).listing()
|
||||
return s
|
||||
|
||||
def query(self):
|
||||
#no need to worry when working from the cache
|
||||
@@ -372,9 +350,21 @@ class HotController(FixListing, ListingController):
|
||||
def content(self):
|
||||
# only send a spotlight listing for HTML rendering
|
||||
if c.render_style == "html":
|
||||
spotlight = self.spotlight()
|
||||
spotlight = None
|
||||
show_sponsors = not (not c.user.pref_show_sponsors and c.user.gold)
|
||||
show_organic = c.user.pref_organic
|
||||
on_frontpage = isinstance(c.site, DefaultSR)
|
||||
|
||||
if self.requested_ad:
|
||||
spotlight = self.make_requested_ad()
|
||||
elif on_frontpage and show_organic:
|
||||
spotlight = self.make_spotlight()
|
||||
elif show_sponsors:
|
||||
spotlight = self.make_single_ad()
|
||||
|
||||
if spotlight:
|
||||
return PaneStack([spotlight, self.listing_obj], css_class='spacer')
|
||||
return PaneStack([spotlight, self.listing_obj],
|
||||
css_class='spacer')
|
||||
return self.listing_obj
|
||||
|
||||
def title(self):
|
||||
|
||||
@@ -44,7 +44,7 @@ from r2.lib.memoize import memoize
|
||||
from r2.lib.organic import keep_fresh_links
|
||||
from r2.lib.strings import strings
|
||||
from r2.lib.template_helpers import get_domain
|
||||
from r2.lib.utils import UniqueIterator, tup, to_date
|
||||
from r2.lib.utils import UniqueIterator, tup, to_date, weighted_lottery
|
||||
from r2.models import (
|
||||
Account,
|
||||
AdWeight,
|
||||
@@ -838,15 +838,22 @@ def get_promotion_list_cached(sites):
|
||||
for link, weight, campaign in promos]
|
||||
|
||||
|
||||
def sample_promoted_links(user, site, n=10):
|
||||
"""Return a random selection of promoted links.
|
||||
|
||||
Does not factor weights, as that will be done client side.
|
||||
|
||||
"""
|
||||
|
||||
def lottery_promoted_links(user, site, n=10):
|
||||
"""Run weighted_lottery to order and choose a subset of promoted links."""
|
||||
promo_tuples = get_promotion_list(user, site)
|
||||
if n >= len(promo_tuples):
|
||||
weights = {p: p.weight for p in promo_tuples}
|
||||
selected = []
|
||||
while weights and len(selected) < n:
|
||||
s = weighted_lottery(weights)
|
||||
del weights[s]
|
||||
selected.append(s)
|
||||
return selected
|
||||
|
||||
|
||||
def sample_promoted_links(user, site, n=10):
|
||||
"""Return a selection of promoted links."""
|
||||
promo_tuples = get_promotion_list(user, site)
|
||||
if len(promo_tuples) <= n:
|
||||
return promo_tuples
|
||||
else:
|
||||
return random.sample(promo_tuples, n)
|
||||
|
||||
@@ -490,11 +490,12 @@ class IDBuilder(QueryBuilder):
|
||||
class CampaignBuilder(IDBuilder):
|
||||
"""Build on a list of PromoTuples."""
|
||||
|
||||
def __init__(self, query, wrap=Wrapped, keep_fn=None, prewrap_fn=None):
|
||||
def __init__(self, query, wrap=Wrapped, keep_fn=None, prewrap_fn=None,
|
||||
skip=False, num=None):
|
||||
Builder.__init__(self, wrap=wrap, keep_fn=keep_fn)
|
||||
self.query = query
|
||||
self.skip = False
|
||||
self.num = None
|
||||
self.skip = skip
|
||||
self.num = num
|
||||
self.start_count = 0
|
||||
self.after = None
|
||||
self.reverse = False
|
||||
|
||||
Reference in New Issue
Block a user