From 0dce9b97a7f262a4e623b2af1718ba76e894ddfe Mon Sep 17 00:00:00 2001 From: Brian Simpson Date: Fri, 18 Oct 2013 08:01:57 -0400 Subject: [PATCH] Delete Promote_Graph. --- r2/r2/config/routing.py | 1 - r2/r2/controllers/promotecontroller.py | 38 ----- r2/r2/lib/menus.py | 1 - r2/r2/lib/pages/pages.py | 192 ------------------------- r2/r2/public/static/css/reddit.less | 64 --------- r2/r2/templates/promote_graph.html | 184 ------------------------ 6 files changed, 480 deletions(-) delete mode 100644 r2/r2/templates/promote_graph.html diff --git a/r2/r2/config/routing.py b/r2/r2/config/routing.py index d4c84cefe..d7790c9ce 100644 --- a/r2/r2/config/routing.py +++ b/r2/r2/config/routing.py @@ -208,7 +208,6 @@ def make_map(): controller='promote', action='pay') mc('/promoted/refund/:link/:campaign', controller='promote', action='refund') - mc('/promoted/admin/graph', controller='promote', action='admingraph') mc('/promoted/:action', controller='promote', requirements=dict(action="edit_promo|new_promo|roadblock")) diff --git a/r2/r2/controllers/promotecontroller.py b/r2/r2/controllers/promotecontroller.py index 451e0a145..28d1229db 100644 --- a/r2/r2/controllers/promotecontroller.py +++ b/r2/r2/controllers/promotecontroller.py @@ -22,7 +22,6 @@ from datetime import datetime, timedelta from babel.numbers import format_number -import itertools import json import urllib @@ -40,7 +39,6 @@ from r2.lib.menus import NamedButton, NavButton, NavMenu from r2.lib.pages import ( LinkInfoPage, PaymentForm, - Promote_Graph, PromotePage, PromoteLinkForm, PromoteLinkNew, @@ -107,27 +105,6 @@ from r2.models import ( ) -def _check_dates(dates): - params = ('startdate', 'enddate') - error_types = (errors.BAD_DATE, - errors.DATE_TOO_EARLY, - errors.DATE_TOO_LATE, - errors.BAD_DATE_RANGE, - errors.DATE_RANGE_TOO_LARGE) - for error_case in itertools.product(error_types, params): - if error_case in c.errors: - bad_dates = dates - start, end = None, None - break - else: - bad_dates = None - start, end = dates - if not start or not end: - start = promote.promo_datetime_now(offset=-7).date() - end = promote.promo_datetime_now(offset=6).date() - return start, end, bad_dates - - def campaign_has_oversold_error(form, campaign): if campaign.priority.inventory_override: return @@ -323,21 +300,6 @@ class PromoteController(ListingController): datestr=True) return {'inventory': available_by_datestr} - @validate(VSponsor(), - dates=VDateRange(["startdate", "enddate"], - max_range=timedelta(days=28), - required=False)) - @validate(VSponsorAdmin(), - dates=VDateRange(["startdate", "enddate"], - max_range=timedelta(days=28), - required=False)) - def GET_admingraph(self, dates): - start, end, bad_dates = _check_dates(dates) - content = Promote_Graph(start, end, bad_dates=bad_dates) - if c.render_style == 'csv': - return content.as_csv() - return PromotePage("admingraph", content=content).render() - # ## POST controllers below @validatedForm(VSponsorAdmin(), link=VLink("link_id"), diff --git a/r2/r2/lib/menus.py b/r2/r2/lib/menus.py index 0a9928bde..272540b00 100644 --- a/r2/r2/lib/menus.py +++ b/r2/r2/lib/menus.py @@ -167,7 +167,6 @@ menu = MenuHandler(hot = _('hot'), all_promos = _('all'), future_promos = _('unseen'), roadblock = _('roadblock'), - admin_graph = _('admin analytics'), live_promos = _('live'), unpaid_promos = _('unpaid'), pending_promos = _('pending'), diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py index dcb8a1d76..c5af97c75 100644 --- a/r2/r2/lib/pages/pages.py +++ b/r2/r2/lib/pages/pages.py @@ -3427,8 +3427,6 @@ class PromotePage(Reddit): buttons.append(NamedButton('my_current_promos', dest = '')) if c.user_is_sponsor: - buttons.append(NamedButton('admin_graph', - dest='/admin/graph')) buttons.append(NavButton('report', 'report')) buttons.append(NavButton('underdelivered', 'underdelivered')) buttons.append(NavButton('house ads', 'house')) @@ -3788,196 +3786,6 @@ class Promotion_Summary(Templated): % ndays, p.render('email')) -def force_datetime(d): - return datetime.datetime.combine(d, datetime.time()) - - -class Promote_Graph(Templated): - - @classmethod - @memoize('get_market', time = 60) - def get_market(cls, user_id, start_date, end_date): - market = {} - promo_counter = {} - def callback(link, bid_day, starti, endi, campaign): - for i in xrange(starti, endi): - if user_id is None or link.author_id == user_id: - if (not promote.is_unpaid(link) and - not promote.is_rejected(link) and - campaign.trans_id != NO_TRANSACTION): - market[i] = market.get(i, 0) + bid_day - promo_counter[i] = promo_counter.get(i, 0) + 1 - cls.promo_iter(start_date, end_date, callback) - return market, promo_counter - - @classmethod - def promo_iter(cls, start_date, end_date, callback): - size = (end_date - start_date).days - current_promos = cls.get_current_promos(start_date, end_date) - campaign_ids = [camp_id for link, camp_id, s, e in current_promos] - campaigns = PromoCampaign._byID(campaign_ids, data=True) - for link, campaign_id, s, e in current_promos: - if campaign_id in campaigns: - campaign = campaigns[campaign_id] - sdate = campaign.start_date.date() - edate = campaign.end_date.date() - starti = max((sdate - start_date).days, 0) - endi = min((edate - start_date).days, size) - bid_day = campaign.bid / max((edate - sdate).days, 1) - callback(link, bid_day, starti, endi, campaign) - - @classmethod - def get_current_promos(cls, start_date, end_date): - # grab promoted links - # returns a list of (thing_id, campaign_idx, start, end) - promos = PromotionWeights.get_schedule(start_date, end_date) - # sort based on the start date - promos.sort(key = lambda x: x[2]) - - # wrap the links - links = wrap_links([p[0] for p in promos]) - # remove rejected/unpaid promos - links = dict((l._fullname, l) for l in links.things - if promote.is_accepted(l) or promote.is_unapproved(l)) - # filter promos accordingly - promos = [(links[thing_name], campaign_id, s, e) - for thing_name, campaign_id, s, e in promos - if links.has_key(thing_name)] - - return promos - - def __init__(self, start_date, end_date, bad_dates=None): - self.now = promote.promo_datetime_now() - - start_date = to_date(start_date) - end_date = to_date(end_date) - end_before = end_date + datetime.timedelta(days=1) - - size = (end_before - start_date).days - self.dates = [start_date + datetime.timedelta(i) for i in xrange(size)] - - # these will be cached queries - market, promo_counter = self.get_market(None, start_date, end_before) - my_market = market - - # determine the range of each link - promote_blocks = [] - def block_maker(link, bid_day, starti, endi, campaign): - if (not promote.is_rejected(link) - and not promote.is_unpaid(link)): - promote_blocks.append((link, starti, endi, campaign)) - self.promo_iter(start_date, end_before, block_maker) - - # now sort the promoted_blocks into the most contiguous chuncks we can - sorted_blocks = [] - while promote_blocks: - cur = promote_blocks.pop(0) - while True: - sorted_blocks.append(cur) - # get the future items (sort will be preserved) - future = filter(lambda x: x[2] >= cur[3], promote_blocks) - if future: - # resort by date and give precidence to longest promo: - cur = min(future, key = lambda x: (x[2], x[2]-x[3])) - promote_blocks.remove(cur) - else: - break - - pool =PromotionWeights.bid_history(promote.promo_datetime_now(offset=-30), - promote.promo_datetime_now(offset=2)) - - # graphs of impressions and clicks - self.promo_traffic = promote.traffic_totals() - - impressions = [(d, i) for (d, (i, k)) in self.promo_traffic] - pool = dict((d, b+r) for (d, b, r) in pool) - - if impressions: - CPM = [(force_datetime(d), (pool.get(d, 0) * 1000. / i) if i else 0) - for (d, (i, k)) in self.promo_traffic if d in pool] - mean_CPM = sum(x[1] for x in CPM) * 1. / max(len(CPM), 1) - - CPC = [(force_datetime(d), (100 * pool.get(d, 0) / k) if k else 0) - for (d, (i, k)) in self.promo_traffic if d in pool] - mean_CPC = sum(x[1] for x in CPC) * 1. / max(len(CPC), 1) - - cpm_title = _("cost per 1k impressions ($%(avg).2f average)") % dict(avg=mean_CPM) - cpc_title = _("cost per click ($%(avg).2f average)") % dict(avg=mean_CPC/100.) - - data = traffic.zip_timeseries(((d, (min(v, mean_CPM * 2),)) for d, v in CPM), - ((d, (min(v, mean_CPC * 2),)) for d, v in CPC)) - - from r2.lib.pages.trafficpages import COLORS # not top level because of * imports :( - self.performance_table = TimeSeriesChart("promote-graph-table", - _("historical performance"), - "day", - [dict(color=COLORS.DOWNVOTE_BLUE, - title=cpm_title, - shortname=_("CPM")), - dict(color=COLORS.DOWNVOTE_BLUE, - title=cpc_title, - shortname=_("CPC"))], - data) - else: - self.performance_table = None - - self.promo_traffic = dict(self.promo_traffic) - - predicted = inventory.get_predicted_by_date(None, start_date, - end_before) - self.impression_inventory = predicted - # TODO: Real data - self.scheduled_impressions = dict.fromkeys(predicted, 0) - - self.cpc = {} - self.cpm = {} - self.delivered = {} - self.clicked = {} - self.my_market = {} - self.promo_counter = {} - - today = self.now.date() - for i in xrange(size): - day = start_date + datetime.timedelta(i) - cpc = cpm = delivered = clicks = "---" - if day in self.promo_traffic: - delivered, clicks = self.promo_traffic[day] - if i in market and day < today: - cpm = "$%.2f" % promote.cost_per_mille(market[i], delivered) - cpc = "$%.2f" % promote.cost_per_click(market[i], clicks) - delivered = format_number(delivered, c.locale) - clicks = format_number(clicks, c.locale) - if day == today: - delivered = "(%s)" % delivered - clicks = "(%s)" % clicks - self.cpc[day] = cpc - self.cpm[day] = cpm - self.delivered[day] = delivered - self.clicked[day] = clicks - if i in my_market: - self.my_market[day] = "$%.2f" % my_market[i] - else: - self.my_market[day] = "---" - self.promo_counter[day] = promo_counter.get(i, "---") - - Templated.__init__(self, today=today, promote_blocks=sorted_blocks, - start_date=start_date, end_date=end_date, - bad_dates=bad_dates) - - def to_iter(self, localize = True): - locale = c.locale - def num(x): - if localize: - return format_number(x, locale) - return str(x) - for link, uimp, nimp, ucli, ncli in self.recent: - yield (link._date.strftime("%Y-%m-%d"), - num(uimp), num(nimp), num(ucli), num(ncli), - num(link._ups - link._downs), - "$%.2f" % link.promote_bid, - _force_unicode(link.title)) - - class PromoteReport(Templated): def __init__(self, links, link_text, owner_name, bad_links, start, end): self.links = links diff --git a/r2/r2/public/static/css/reddit.less b/r2/r2/public/static/css/reddit.less index e135e5922..d10e60962 100755 --- a/r2/r2/public/static/css/reddit.less +++ b/r2/r2/public/static/css/reddit.less @@ -5248,70 +5248,6 @@ button.new-campaign:disabled { color: gray; } dt { margin-left: 10px; font-weight: bold; } dd { margin-left: 20px; } -.calendar-lead { - margin: 15px; -} - -table.calendar { - white-space: nowrap; - width: 90%; - margin-top: 20px; - position: relative; - padding-top: 120px; - padding-bottom: 100px; - empty-cells: show; - table-layout: fixed; -} - -.calendar .today { - background-color: yellow; -} - -.calendar thead tr { - border-bottom: 2px solid gray; -} - -.calendar thead th, .calendar thead td { - font-weight: bold; - text-align: center; - text-transform: uppercase; -} - -.calendar td, .calendar th[scope="col"] { - border-left: 1px dashed gray; -} - -.calendar .blob { - margin: 0; - padding: 0px; - z-index: 10; - cursor: pointer; -} - -.calendar .blob.link:hover { - border: 1px solid red; - box-shadow: 2px 2px 2px #000; - -moz-box-shadow: 2px 2px 2px #000; - z-index: 100; -} - -.calendar .blob .bid { - text-align: right; - font-weight: bold; - padding: 5px 5px 0px 5px; -} - -.calendar .blob.link { - margin: -1px -2px 0px -2px; - border: 1px solid black; -} - -.calendar .blob.link .title{ - font-size: small; - padding: 0 5px 5px 5px; - display: block; -} - .borderless td { border: none; } diff --git a/r2/r2/templates/promote_graph.html b/r2/r2/templates/promote_graph.html deleted file mode 100644 index c6b0542c1..000000000 --- a/r2/r2/templates/promote_graph.html +++ /dev/null @@ -1,184 +0,0 @@ -## The contents of this file are subject to the Common Public Attribution -## License Version 1.0. (the "License"); you may not use this file except in -## compliance with the License. You may obtain a copy of the License at -## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public -## License Version 1.1, but Sections 14 and 15 have been added to cover use of -## software over a computer network and provide for limited attribution for the -## Original Developer. In addition, Exhibit A has been modified to be -## consistent with Exhibit B. -## -## Software distributed under the License is distributed on an "AS IS" basis, -## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -## the specific language governing rights and limitations under the License. -## -## The Original Code is reddit. -## -## The Original Developer is the Initial Developer. The Initial Developer of -## the Original Code is reddit Inc. -## -## All portions of the code written by reddit are Copyright (c) 2006-2013 -## reddit Inc. All Rights Reserved. -############################################################################### - -<%! - from r2.lib import js - from r2.lib.template_helpers import static -%> - -<%namespace file="reddittraffic.html" import="load_timeseries_js"/> -<%namespace name="pr" file="promotelinkform.html" /> - -${load_timeseries_js()} -${unsafe(js.use('sponsored'))} - -

${_("Sponsored link calendar")}

-
-

${_("Viewing calendar for dates:")}

- -%if thing.bad_dates and all(thing.bad_dates): -
- ${_("Sorry, I couldn't make sense of the date range: %(start)s - %(end)s") %\ - dict(start=thing.bad_dates[0].strftime('%m/%d/%Y'), - end=thing.bad_dates[1].strftime('%m/%d/%Y'))} -
-%endif - -
- <%pr:datepicker name="startdate" value="${thing.start_date.strftime('%m/%d/%Y')}" - minDateSrc="date-min" initfuncname="init_startdate" - min_date_offset="86400000"> - function(elem) { check_enddate(elem, $("#enddate")); return elem; } - -  –  - <%pr:datepicker name="enddate" value="${thing.end_date.strftime('%m/%d/%Y')}" - minDateSrc="startdate" initfuncname="init_enddate" - min_date_offset="86400000"> - function(elem) { return elem; } - - -
-
- - - - - - %for date in thing.dates: - - %endfor - - - ## TRANSLATORS: Noun - - %for date in thing.dates: - - %endfor - - %if thing.scheduled_impressions: - - ## TRANSLATORS: Advertising term; "ad impressions scheduled for delivery" - - %for date in thing.dates: - - %endfor - - %endif - - - %for date in thing.dates: - - %endfor - - - - %for date in thing.dates: - - %endfor - - - - %for date in thing.dates: - - %endfor - - - - - %for link, start, end, campaign in thing.promote_blocks: - - - %for i in xrange(start): - - %endfor - - %for i in xrange(end, len(thing.dates)): - - %endfor - - %endfor - -
${_("Date")} - -
${_("Count")} - ${thing.promo_counter[date]} -
${_("Scheduled")}
- ${_("Inventory")}
- ${thing.scheduled_impressions.get(date, "---")}
- ${thing.impression_inventory.get(date, "---")} -
- ## TRANSLATORS: Advertising term; "ad impressions delivered / shown" - ${_("Impressions")}
- ## TRANSLATORS: Advertising term: "cost per mille" - ${_("CPM")} -
- ${thing.delivered[date]}
- ${thing.cpm[date]} -
- ${_("Clicks")}
- ## TRANSLATORS: Advertising term: "cost per click" - ${_("CPC")} -
- ${thing.clicked[date]}
- ${thing.cpc[date]} -
- %if c.user_is_sponsor: - ## TRANSLATORS: Advertising term: Total value of scheduled ads - ${_("Total Commit")} - %else: - ## TRANSLATORS: Advertising term: Amount spent on scheduled ads - ${_("Your Commit")} - %endif - - ${thing.my_market[date]} -
- -
- -
- -

${_("historical site performance")}

-
- -${thing.performance_table} - - -