From 3ec750698de6b918687ac8a95d660195bccabf0e Mon Sep 17 00:00:00 2001 From: Chad Birch Date: Thu, 23 May 2013 16:19:07 -0700 Subject: [PATCH] Add reddit gold partners --- r2/r2/config/routing.py | 1 + r2/r2/controllers/api.py | 11 +++ r2/r2/controllers/front.py | 3 + r2/r2/lib/pages/pages.py | 13 ++++ r2/r2/lib/strings.py | 1 + r2/r2/models/gold.py | 68 +++++++++++++++++- r2/r2/public/static/css/goldinfo.less | 41 ++++++++++- .../public/static/gold/partner-backblaze.png | Bin 0 -> 11464 bytes r2/r2/public/static/js/gold.js | 23 ++++++ r2/r2/templates/goldinfopage.html | 44 ++++++++---- r2/r2/templates/goldpartnerspage.html | 67 +++++++++++++++++ 11 files changed, 254 insertions(+), 18 deletions(-) create mode 100644 r2/r2/public/static/gold/partner-backblaze.png create mode 100644 r2/r2/templates/goldpartnerspage.html diff --git a/r2/r2/config/routing.py b/r2/r2/config/routing.py index 2f4d7cbf9..f75e0dd8a 100644 --- a/r2/r2/config/routing.py +++ b/r2/r2/config/routing.py @@ -214,6 +214,7 @@ def make_map(): mc('/gold', controller='forms', action="gold") mc('/gold/creditgild/:passthrough', controller='forms', action='creditgild') mc('/gold/about', controller='front', action='gold_info') + mc('/gold/partners', controller='front', action='gold_partners') mc('/gold/thanks', controller='front', action='goldthanks') mc('/password', controller='forms', action="password") diff --git a/r2/r2/controllers/api.py b/r2/r2/controllers/api.py index b498dd6a4..f1968b5f8 100755 --- a/r2/r2/controllers/api.py +++ b/r2/r2/controllers/api.py @@ -849,6 +849,17 @@ class ApiController(RedditController, OAuth2ResourceController): notify_user_added("accept_moderator_invite", c.user, c.user, c.site) jquery.refresh() + @json_validate(VUser(), + VGold(), + VModhash(), + deal=VLength('deal', 100)) + def POST_claim_gold_partner_deal_code(self, responder, deal): + try: + return {'code': GoldPartnerDealCode.claim_code(c.user, deal)} + except GoldPartnerCodesExhaustedError: + return {'error': 'GOLD_PARTNER_CODES_EXHAUSTED', + 'explanation': _("sorry, we're out of codes!")} + @validatedForm(VUser('curpass', default=''), VModhash(), password=VPassword( diff --git a/r2/r2/controllers/front.py b/r2/r2/controllers/front.py index 6a0e813a4..3b8ee962c 100755 --- a/r2/r2/controllers/front.py +++ b/r2/r2/controllers/front.py @@ -1133,6 +1133,9 @@ class FrontController(RedditController, OAuth2ResourceController): def GET_gold_info(self): return GoldInfoPage(_("gold"), show_sidebar=False).render() + def GET_gold_partners(self): + return GoldPartnersPage(_("gold partners"), show_sidebar=False).render() + class FormsController(RedditController): diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py index c77e930d6..aa6de2b23 100755 --- a/r2/r2/lib/pages/pages.py +++ b/r2/r2/lib/pages/pages.py @@ -27,6 +27,7 @@ from r2.models import Friends, All, Sub, NotFound, DomainSR, Random, Mod, Random from r2.models import Link, Printable, Trophy, bidding, PromoCampaign, PromotionWeights, Comment from r2.models import Flair, FlairTemplate, FlairTemplateBySubredditIndex from r2.models import USER_FLAIR, LINK_FLAIR +from r2.models import GoldPartnerDealCode from r2.models.promo import NO_TRANSACTION, PromotionLog from r2.models.token import OAuth2Client, OAuth2AccessToken from r2.models import traffic @@ -3997,6 +3998,18 @@ class GoldInfoPage(BoringPage): } BoringPage.__init__(self, *args, **kwargs) +class GoldPartnersPage(BoringPage): + def __init__(self, *args, **kwargs): + self.prices = { + "gold_month_price": g.gold_month_price, + "gold_year_price": g.gold_year_price, + } + if c.user_is_loggedin: + self.existing_codes = GoldPartnerDealCode.get_codes_for_user(c.user) + else: + self.existing_codes = [] + BoringPage.__init__(self, *args, **kwargs) + class Goldvertisement(Templated): def __init__(self): Templated.__init__(self) diff --git a/r2/r2/lib/strings.py b/r2/r2/lib/strings.py index 5e00ed6b0..2280f49d1 100644 --- a/r2/r2/lib/strings.py +++ b/r2/r2/lib/strings.py @@ -153,6 +153,7 @@ string_dict = dict( gold_summary_anonymous_gift = _("You're about to give %(amount)s of reddit gold to %(recipient)s. It will be an anonymous gift."), gold_summary_comment_gift = _("Want to say thanks to *%(recipient)s* for this comment? Give them a month of [reddit gold](/gold/about)."), gold_summary_comment_page = _("Give *%(recipient)s* a month of [reddit gold](/gold/about) for this comment:"), + gold_partners_description = _('reddit gold members get access to exclusive stuff'), unvotable_message = _("sorry, this has been archived and can no longer be voted on"), account_activity_blurb = _("This page shows a history of recent activity on your account. If you notice unusual activity, you should change your password immediately. Location information is guessed from your computer's IP address and may be wildly wrong, especially for visits from mobile devices. Note: due to a bug, private-use addresses (starting with 10.) sometimes show up erroneously in this list after regular use of the site."), your_current_ip_is = _("You are currently accessing reddit from this IP address: %(address)s."), diff --git a/r2/r2/models/gold.py b/r2/r2/models/gold.py index e3a751407..976b52427 100644 --- a/r2/r2/models/gold.py +++ b/r2/r2/models/gold.py @@ -23,9 +23,17 @@ from r2.lib.db.tdb_sql import make_metadata, index_str, create_table from pylons import g, c +from pylons.i18n import _ from datetime import datetime import sqlalchemy as sa -from sqlalchemy.exc import IntegrityError +from sqlalchemy import func +from sqlalchemy.exc import IntegrityError, OperationalError +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm.exc import NoResultFound +from sqlalchemy.schema import Column +from sqlalchemy.sql import and_ +from sqlalchemy.types import String, Integer from xml.dom.minidom import Document from r2.lib.utils import tup, randstr @@ -42,6 +50,9 @@ ENGINE_NAME = 'authorize' ENGINE = g.dbm.get_engine(ENGINE_NAME) METADATA = make_metadata(ENGINE) +Session = scoped_session(sessionmaker(bind=ENGINE)) +Base = declarative_base(bind=ENGINE) + gold_table = sa.Table('reddit_gold', METADATA, sa.Column('trans_id', sa.String, nullable = False, primary_key = True), @@ -66,6 +77,61 @@ indices = [index_str(gold_table, 'status', 'status'), index_str(gold_table, 'subscr_id', 'subscr_id')] create_table(gold_table, indices) + + +class GoldPartnerCodesExhaustedError(Exception): + pass + + +class GoldPartnerDealCode(Base): + """Promo codes for deals from reddit gold partners.""" + + __tablename__ = "reddit_gold_partner_deal_codes" + + id = Column(Integer, primary_key=True) + deal = Column(String, nullable=False) + code = Column(String, nullable=False) + user = Column(Integer, nullable=True) + + @classmethod + def get_codes_for_user(cls, user): + results = Session.query(cls).filter(cls.user == user._id) + codes = {r.deal: r.code for r in results} + return codes + + @classmethod + def claim_code(cls, user, deal): + # check if they already have a code for this deal and return it + try: + result = (Session.query(cls) + .filter(and_(cls.user == user._id, + cls.deal == deal)) + .one()) + return result.code + except NoResultFound: + pass + + # select an unclaimed code, assign it to the user, and return it + try: + claiming = (Session.query(cls) + .filter(and_(cls.deal == deal, + cls.user == None, + func.pg_try_advisory_lock(cls.id))) + .limit(1) + .one()) + except NoResultFound: + raise GoldPartnerCodesExhaustedError + + claiming.user = user._id + Session.add(claiming) + Session.commit() + + # release the lock + Session.query(func.pg_advisory_unlock_all()).all() + + return claiming.code + + def create_unclaimed_gold (trans_id, payer_email, paying_id, pennies, days, secret, date, subscr_id = None): diff --git a/r2/r2/public/static/css/goldinfo.less b/r2/r2/public/static/css/goldinfo.less index 85c84d11e..0b03baa1c 100644 --- a/r2/r2/public/static/css/goldinfo.less +++ b/r2/r2/public/static/css/goldinfo.less @@ -6,12 +6,12 @@ transform: @arguments; } -section#about-gold, section#postcard, .or-box { +section#about-gold, section#about-gold-partners, section#postcard, .or-box { font-family: "Bitstream Charter", "Hoefler Text", "Palatino Linotype", "Book Antiqua", Palatino, georgia, garamond, FreeSerif, serif; } -section#about-gold { +section#about-gold, section#about-gold-partners { width: 960px; margin: 40px auto; background: url(../gold/inner-bg.jpg) 11px repeat-y; @@ -92,6 +92,18 @@ section#about-gold { } } + .claim-code-button { + .buy-gold-button; + + cursor: pointer; + border-width: 1px; + padding: 3px 5px; + font-size: 16px; + line-height: 20px; + float: right; + margin-top: 5px; + } + header { // could use box-sizing here, but want to look semi-decent in IE7 @width: 960px; @@ -243,6 +255,31 @@ section#about-gold { } } +section#about-gold-partners { + input.code { + font-weight: bold; + font-size: 16px; + float: right; + max-width: 200px; + line-height: 20px; + text-align: center; + } + + span.error { + font-size: 16px; + float: right; + } + + section { + .how-to-use p { + font-size: 13px; + font-style: italic; + margin-top: 10px; + } + } +} + + .or-box { background: #817461; margin: 0 auto; diff --git a/r2/r2/public/static/gold/partner-backblaze.png b/r2/r2/public/static/gold/partner-backblaze.png new file mode 100644 index 0000000000000000000000000000000000000000..841ba56855772b4fd411c35f3d5f02de09077fae GIT binary patch literal 11464 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 Rfzo7{{f;|=Mw+` literal 0 HcmV?d00001 diff --git a/r2/r2/public/static/js/gold.js b/r2/r2/public/static/js/gold.js index e41c46556..ce25c7ac0 100644 --- a/r2/r2/public/static/js/gold.js +++ b/r2/r2/public/static/js/gold.js @@ -13,6 +13,10 @@ r.gold = { }) $('.stripe-submit').on('click', this.makeStripeToken) + + $('section#about-gold-partners').on('click', 'input.code', function() { + $(this).select() + }) }, _toggleCommentGoldForm: function (e) { @@ -183,6 +187,25 @@ r.gold = { ) } return false + }, + + claim_gold_partner_deal_code: function (elem, name) { + $.ajax({ + type: 'POST', + dataType: 'json', + url: '/api/claim_gold_partner_deal_code.json', + data: {'deal': name, 'uh': r.config.modhash}, + success: function(data) { + if ('error' in data) { + var $newelem = $('').text(data['explanation']) + $(elem).replaceWith($newelem) + } else { + var $newelem = $('').attr('value', data['code']) + $(elem).replaceWith($newelem) + $newelem.select() + } + } + }) } }; diff --git a/r2/r2/templates/goldinfopage.html b/r2/r2/templates/goldinfopage.html index 03bc068c2..33d7f0475 100644 --- a/r2/r2/templates/goldinfopage.html +++ b/r2/r2/templates/goldinfopage.html @@ -20,6 +20,7 @@ ## reddit Inc. All Rights Reserved. ############################################################################### <%! + from r2.lib.strings import strings from r2.lib.template_helpers import static %> <%namespace file="less.html" import="less_stylesheet"/> @@ -39,22 +40,38 @@
${_('New!')}
%endif ${_md(description_md)} + %if caller: + ${caller.body()} + %endif +<%def name="goldinfo_header(title, description)"> +
+ +

${title}

+

${description}

+ +
+ + +<%def name="goldinfo_footer()"> +
+

${_('become a member today.')}

+

${_('reddit gold is %(gold_month_price)s / month, or %(gold_year_price)s for a year.') % thing.prices}

+ ${_('buy reddit gold')} +
+ + <%def name="content()">
-
- -

${_('Make reddit better.')}

-

${_('reddit gold adds shiny extra features to your account that are made possible thanks to support from people like you.')}

- -
+ ${goldinfo_header(_('Make reddit better.'), + _('reddit gold adds shiny extra features to your account that are made possible thanks to support from people like you.'))} ${feature_item(static('gold/sample-filterall.png'), _( "# Filter specific subreddits from /r/all.\n" @@ -99,15 +116,12 @@
  • ${_('The Lounge.')} ${_('Access to a super-secret members-only community that may or may not exist.')}
  • ${_('Beta test new features.')} ${_('We occasionally invite gold members to try out new features first.')}
  • +
  • ${_('Deals from gold partners.')} ${strings.gold_partners_description}
  • ${_('A trophy on your user page.')} ${_('As thanks for supporting reddit gold.')}
  • ${_('More to come.')} ${_("We have many more ideas for gold features, and will add to this list in the future.")}
-
-

${_('become a member today.')}

-

${_('reddit gold is %(gold_month_price)s / month, or %(gold_year_price)s for a year.') % thing.prices}

- ${_('buy reddit gold')} -
+ ${goldinfo_footer()}
${_('or')}
diff --git a/r2/r2/templates/goldpartnerspage.html b/r2/r2/templates/goldpartnerspage.html new file mode 100644 index 000000000..e9fe2b23a --- /dev/null +++ b/r2/r2/templates/goldpartnerspage.html @@ -0,0 +1,67 @@ +## 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.strings import strings + from r2.lib.template_helpers import static +%> +<%namespace file="goldinfopage.html" import="feature_item, goldinfo_header, goldinfo_footer"/> +<%namespace file="less.html" import="less_stylesheet"/> +<%namespace file="utils.html" import="_md"/> +<%inherit file="reddit.html"/> + +<%def name="stylesheet()"> + ${parent.stylesheet()} + ${less_stylesheet('goldinfo.less')} + + +<%def name="partner_item(name, how_to_use, img_src, description_md, extra_class='')"> + <%call expr="feature_item(img_src, description_md, extra_class)"> + %if c.user.gold: +
+ ${_md(how_to_use)} +
+ %endif + %if name in thing.existing_codes: + + %elif c.user.gold: +
${_('claim code')} + %else: + ${_('buy reddit gold')} + %endif + + + +<%def name="content()"> +
+ ${goldinfo_header(_('reddit gold partners'), + strings.gold_partners_description)} + + ${partner_item('backblaze', + _("Claim your code below, then visit https://secure.backblaze.com/gift/XXXXXXX (replacing Xs with your code), and click 'Redeem & Download' to install the product and enter your email/password."), + static('gold/partner-backblaze.png'), + _('# Backblaze Online Backup\n' + '3 months of free service from Backblaze Online Backup.'), + 'new')} + + ${goldinfo_footer()} +
+