Gilding: add support for gilding submissions

This commit is contained in:
Chad Birch
2014-02-11 14:19:03 -07:00
parent aff92cc6fa
commit 3b28ff52bc
26 changed files with 547 additions and 338 deletions

View File

@@ -3764,21 +3764,21 @@ class ApiController(RedditController):
@json_validate(VUser(),
VModhash(),
comment=VByName("comment", thing_cls=Comment))
def POST_generate_payment_blob(self, responder, comment):
if not comment:
thing=VByName("thing"))
def POST_generate_payment_blob(self, responder, thing):
if not thing:
abort(400, "Bad Request")
if comment._deleted:
if thing._deleted:
abort(403, "Forbidden")
comment_sr = Subreddit._byID(comment.sr_id, data=True)
if (not comment_sr.can_view(c.user) or
not comment_sr.allow_comment_gilding):
thing_sr = Subreddit._byID(thing.sr_id, data=True)
if (not thing_sr.can_view(c.user) or
not thing_sr.allow_gilding):
abort(403, "Forbidden")
try:
recipient = Account._byID(comment.author_id, data=True)
recipient = Account._byID(thing.author_id, data=True)
except NotFound:
self.abort404()
@@ -3793,7 +3793,7 @@ class ApiController(RedditController):
signed=False,
recipient=recipient.name,
giftmessage=None,
comment=comment._fullname,
thing=thing._fullname,
))
@validate(srnames=VPrintable("srnames", max_length=2100))

View File

@@ -1422,25 +1422,35 @@ class FormsController(RedditController):
if not payment_blob['goldtype'] == 'gift':
self.abort404()
comment = payment_blob['comment']
if (not comment or
comment._deleted or
not comment.subreddit_slow.can_view(c.user)):
recipient = payment_blob['recipient']
thing = payment_blob.get('thing')
if not thing:
thing = payment_blob['comment']
if (not thing or
thing._deleted or
not thing.subreddit_slow.can_view(c.user)):
self.abort404()
recipient = payment_blob['recipient']
summary = strings.gold_summary_comment_page
if isinstance(thing, Comment):
summary = strings.gold_summary_gilding_page_comment
else:
summary = strings.gold_summary_gilding_page_link
summary = summary % {'recipient': recipient.name}
months = 1
price = g.gold_month_price * months
if isinstance(thing, Comment):
desc = thing.body
else:
desc = thing.markdown_link_slow()
content = CreditGild(
summary=summary,
price=price,
months=months,
stripe_key=g.STRIPE_PUBLIC_KEY,
passthrough=passthrough,
comment=comment,
description=desc,
period=None,
)
@@ -1457,17 +1467,18 @@ class FormsController(RedditController):
# variables below are just for gifts
signed=VBoolean("signed"),
recipient_name=VPrintable("recipient", max_length=50),
comment=VByName("comment", thing_cls=Comment),
thing=VByName("thing"),
giftmessage=VLength("giftmessage", 10000))
def GET_gold(self, goldtype, period, months,
signed, recipient_name, giftmessage, comment):
signed, recipient_name, giftmessage, thing):
if comment:
comment_sr = Subreddit._byID(comment.sr_id, data=True)
if (comment._deleted or comment._spam or
not comment_sr.can_view(c.user) or
not comment_sr.allow_comment_gilding):
comment = None
if thing:
thing_sr = Subreddit._byID(thing.sr_id, data=True)
if (thing._deleted or
thing._spam or
not thing_sr.can_view(c.user) or
not thing_sr.allow_gilding):
thing = None
start_over = False
recipient = None
@@ -1483,10 +1494,10 @@ class FormsController(RedditController):
if months is None or months < 1:
start_over = True
if comment:
recipient = Account._byID(comment.author_id, data=True)
if thing:
recipient = Account._byID(thing.author_id, data=True)
if recipient._deleted:
comment = None
thing = None
recipient = None
start_over = True
else:
@@ -1515,8 +1526,8 @@ class FormsController(RedditController):
payment_blob["signed"] = signed
payment_blob["recipient"] = recipient.name
payment_blob["giftmessage"] = _force_utf8(giftmessage)
if comment:
payment_blob["comment"] = comment._fullname
if thing:
payment_blob["thing"] = thing._fullname
passthrough = generate_blob(payment_blob)
@@ -1525,7 +1536,7 @@ class FormsController(RedditController):
content=GoldPayment(goldtype, period, months,
signed, recipient,
giftmessage, passthrough,
comment)
thing)
).render()
@validate(VUser())

View File

@@ -62,7 +62,8 @@ from r2.models import (
create_gift_gold,
create_gold_code,
get_discounted_price,
make_comment_gold_message,
Link,
make_gold_message,
NotFound,
retrieve_gold_transaction,
send_system_message,
@@ -225,14 +226,15 @@ def months_and_days_from_pennies(pennies, discount=False):
days = 31 * months
return (months, days)
def send_gift(buyer, recipient, months, days, signed, giftmessage, comment_id):
def send_gift(buyer, recipient, months, days, signed, giftmessage,
thing_fullname):
admintools.engolden(recipient, days)
if comment_id:
comment = Thing._by_fullname(comment_id, data=True)
comment._gild(buyer)
if thing_fullname:
thing = Thing._by_fullname(thing_fullname, data=True)
thing._gild(buyer)
else:
comment = None
thing = None
if signed:
sender = buyer.name
@@ -248,17 +250,20 @@ def send_gift(buyer, recipient, months, days, signed, giftmessage, comment_id):
else:
amount = "%d months" % months
if not comment:
if not thing:
subject = _('Let there be gold! %s just sent you reddit gold!') % sender
message = strings.youve_got_gold % dict(sender=md_sender, amount=amount)
if giftmessage and giftmessage.strip():
message += "\n\n" + strings.giftgold_note + giftmessage + '\n\n----'
else:
subject = _('Your comment has been gilded!')
message = strings.youve_got_comment_gold % dict(
url=comment.make_permalink_slow(),
)
url = thing.make_permalink_slow()
if isinstance(thing, Comment):
subject = _('Your comment has been gilded!')
message = strings.youve_been_gilded_comment % {'url': url}
else:
subject = _('Your submission has been gilded!')
message = strings.youve_been_gilded_link % {'url': url}
message += '\n\n' + strings.gold_benefits_msg
if g.lounge_reddit:
@@ -272,7 +277,7 @@ def send_gift(buyer, recipient, months, days, signed, giftmessage, comment_id):
g.log.error('send_gift: could not send system message')
g.log.info("%s gifted %s to %s" % (buyer.name, amount, recipient.name))
return comment
return thing
def send_gold_code(buyer, months, days,
@@ -354,9 +359,9 @@ class IpnController(RedditController):
c.user._commit()
if payment_blob["goldtype"] == "gift":
comment_id = payment_blob.get("comment")
comment = send_gift(c.user, recipient, months, days, signed,
giftmessage, comment_id)
thing_fullname = payment_blob.get("thing")
thing = send_gift(c.user, recipient, months, days, signed,
giftmessage, thing_fullname)
form.set_html(".status", _("the gold has been delivered!"))
else:
try:
@@ -368,7 +373,7 @@ class IpnController(RedditController):
"for assistance.")
% {'email': g.goldthanks_email})
return
comment = None
thing = None
form.set_html(".status",
_("the gift code has been messaged to you!"))
@@ -380,10 +385,9 @@ class IpnController(RedditController):
payment_blob["status"] = "processed"
g.hardcache.set(blob_key, payment_blob, 86400 * 30)
if comment:
gilding_message = make_comment_gold_message(comment,
user_gilded=True)
jquery.gild_comment(comment_id, gilding_message, comment.gildings)
if thing:
gilding_message = make_gold_message(thing, user_gilded=True)
jquery.gild_thing(thing_fullname, gilding_message, thing.gildings)
@textresponse(paypal_secret = VPrintable('secret', 50),
payment_status = VPrintable('payment_status', 20),
@@ -527,8 +531,9 @@ class IpnController(RedditController):
% (recipient_name, custom))
signed = payment_blob.get("signed", False)
giftmessage = _force_unicode(payment_blob.get("giftmessage", ""))
comment_id = payment_blob.get("comment")
send_gift(buyer, recipient, months, days, signed, giftmessage, comment_id)
thing_fullname = payment_blob.get("thing")
send_gift(buyer, recipient, months, days, signed, giftmessage,
thing_fullname)
instagift = True
subject = _("Thanks for giving the gift of reddit gold!")
message = _("Your classy gift to %s has been delivered.\n\n"
@@ -576,7 +581,7 @@ class Webhook(object):
def __init__(self, passthrough=None, transaction_id=None, subscr_id=None,
pennies=None, months=None, payer_email='', payer_id='',
goldtype=None, buyer=None, recipient=None, signed=False,
giftmessage=None, comment=None):
giftmessage=None, thing=None):
self.passthrough = passthrough
self.transaction_id = transaction_id
self.subscr_id = subscr_id
@@ -589,7 +594,7 @@ class Webhook(object):
self.recipient = recipient
self.signed = signed
self.giftmessage = giftmessage
self.comment = comment
self.thing = thing
def load_blob(self):
payment_blob = validate_blob(self.passthrough)
@@ -598,8 +603,8 @@ class Webhook(object):
self.recipient = payment_blob.get('recipient')
self.signed = payment_blob.get('signed', False)
self.giftmessage = payment_blob.get('giftmessage')
comment = payment_blob.get('comment')
self.comment = comment._fullname if comment else None
thing = payment_blob.get('thing')
self.thing = thing._fullname if thing else None
def __repr__(self):
return '<%s: transaction %s>' % (self.__class__.__name__, self.transaction_id)
@@ -720,7 +725,7 @@ class GoldPaymentController(RedditController):
recipient = webhook.recipient
signed = webhook.signed
giftmessage = webhook.giftmessage
comment = webhook.comment
thing = webhook.thing
gold_recipient = recipient or buyer
with gold_lock(gold_recipient):
@@ -753,7 +758,7 @@ class GoldPaymentController(RedditController):
elif goldtype == 'gift':
send_gift(buyer, recipient, months, days, signed, giftmessage,
comment)
thing)
subject = "thanks for giving reddit gold!"
message = "Your gift to %s has been delivered." % recipient.name
@@ -1183,12 +1188,12 @@ def validate_blob(custom):
ret['recipient'] = recipient
except NotFound:
raise GoldException('bad recipient')
comment_fullname = payment_blob.get('comment', None)
if comment_fullname:
thing_fullname = payment_blob.get('thing', None)
if thing_fullname:
try:
ret['comment'] = Comment._by_fullname(comment_fullname)
ret['thing'] = Thing._by_fullname(thing_fullname)
except NotFound:
raise GoldException('bad comment')
raise GoldException('bad thing')
ret['signed'] = payment_blob.get('signed', False)
giftmessage = payment_blob.get('giftmessage')
giftmessage = _force_unicode(giftmessage) if giftmessage else None

View File

@@ -520,8 +520,8 @@ class UserController(ListingController):
elif (self.where == 'gilded' and
(c.user == self.vuser or c.user_is_admin)):
path = '/user/%s/gilded/' % self.vuser.name
buttons = [NavButton(_("my posts"), dest='/'),
NavButton(_("posts gilded by me"), dest='/given')]
buttons = [NavButton(_("gildings received"), dest='/'),
NavButton(_("gildings given"), dest='/given')]
res.append(NavMenu(buttons, base_path=path, type='flatlist'))
return res
@@ -530,14 +530,14 @@ class UserController(ListingController):
titles = {'overview': _("overview for %(user)s"),
'comments': _("comments by %(user)s"),
'submitted': _("submitted by %(user)s"),
'gilded': _("gilded comments by %(user)s"),
'gilded': _("gilded by %(user)s"),
'liked': _("liked by %(user)s"),
'disliked': _("disliked by %(user)s"),
'saved': _("saved by %(user)s"),
'hidden': _("hidden by %(user)s"),
'promoted': _("promoted by %(user)s")}
if self.where == 'gilded' and self.show == 'given':
return _("comments gilded by %(user)s") % {'user': self.vuser.name}
return _("gildings given by %(user)s") % {'user': self.vuser.name}
title = titles.get(self.where, _('profile for %(user)s')) \
% dict(user = self.vuser.name, site = c.site.name)
@@ -598,7 +598,7 @@ class UserController(ListingController):
if self.show == 'given':
q = queries.get_user_gildings(self.vuser)
else:
q = queries.get_gilded_user_comments(self.vuser)
q = queries.get_gilded_user(self.vuser)
elif self.where in ('liked', 'disliked'):
sup.set_sup_header(self.vuser, self.where)
@@ -1306,7 +1306,7 @@ class UserListListingController(ListingController):
return self.build_listing(**kw)
class GildedController(ListingController):
title_text = _("gilded comments")
title_text = _("gilded")
def keep_fn(self):
def keep(item):
@@ -1315,7 +1315,7 @@ class GildedController(ListingController):
def query(self):
try:
return c.site.get_gilded_comments()
return c.site.get_gilded()
except NotImplementedError:
abort(404)

View File

@@ -797,18 +797,60 @@ def get_all_gilded_comments():
return
@cached_query(SubredditQueryCache, sort=[desc("date")], filter_fn=filter_thing)
def get_all_gilded_links():
return
@merged_cached_query
def get_all_gilded():
return [get_all_gilded_comments(), get_all_gilded_links()]
@cached_query(SubredditQueryCache, sort=[desc("date")], filter_fn=filter_thing)
def get_gilded_comments(sr_id):
return
@cached_query(SubredditQueryCache, sort=[desc("date")], filter_fn=filter_thing)
def get_gilded_links(sr_id):
return
@merged_cached_query
def get_gilded(sr_ids):
queries = [get_gilded_links, get_gilded_comments]
return [query(sr_id)
for sr_id, query in itertools.product(tup(sr_ids), queries)]
@cached_query(UserQueryCache, sort=[desc("date")], filter_fn=filter_thing)
def get_gilded_user_comments(user_id):
return
@cached_query(UserQueryCache, sort=[desc("date")], filter_fn=filter_thing)
def get_gilded_user_links(user_id):
return
@merged_cached_query
def get_gilded_users(user_ids):
queries = [get_gilded_user_links, get_gilded_user_comments]
return [query(user_id)
for user_id, query in itertools.product(tup(user_ids), queries)]
@cached_query(UserQueryCache, sort=[desc("date")], filter_fn=filter_thing)
def get_user_gildings(user_id):
return
@merged_cached_query
def get_gilded_user(user):
return [get_gilded_user_comments(user), get_gilded_user_links(user)]
def add_queries(queries, insert_items=None, delete_items=None, foreground=False):
"""Adds multiple queries to the query queue. If insert_items or
delete_items is specified, the query may not need to be

View File

@@ -409,6 +409,7 @@ class LinkJsonTemplate(ThingJsonTemplate):
domain="domain",
downs="downvotes",
edited="editted",
gilded="gildings",
hidden="hidden",
is_self="is_self",
likes="likes",

View File

@@ -247,17 +247,30 @@ class Reddit(Templated):
and not is_api() and not self.show_wiki_actions):
# insert some form templates for js to use
# TODO: move these to client side templates
gold = GoldPayment("gift",
"monthly",
months=1,
signed=False,
recipient="",
giftmessage=None,
passthrough=None,
comment=None,
clone_template=True,
)
self._content = PaneStack([ShareLink(), content, gold])
gold_link = GoldPayment("gift",
"monthly",
months=1,
signed=False,
recipient="",
giftmessage=None,
passthrough=None,
thing=None,
clone_template=True,
thing_type="link",
)
gold_comment = GoldPayment("gift",
"monthly",
months=1,
signed=False,
recipient="",
giftmessage=None,
passthrough=None,
thing=None,
clone_template=True,
thing_type="comment",
)
self._content = PaneStack([ShareLink(), content,
gold_comment, gold_link])
else:
self._content = content
@@ -2184,9 +2197,10 @@ class Gold(Templated):
class GoldPayment(Templated):
def __init__(self, goldtype, period, months, signed,
recipient, giftmessage, passthrough, comment,
clone_template=False):
recipient, giftmessage, passthrough, thing,
clone_template=False, thing_type=None):
pay_from_creddits = False
desc = None
if period == "monthly" or 1 <= months < 12:
unit_price = g.gold_month_price
@@ -2267,9 +2281,17 @@ class GoldPayment(Templated):
amount=Score.somethings(months, "month"))
elif goldtype == "gift":
if clone_template:
format = strings.gold_summary_comment_gift
elif comment:
format = strings.gold_summary_comment_page
if thing_type == "comment":
format = strings.gold_summary_gilding_comment
elif thing_type == "link":
format = strings.gold_summary_gilding_link
elif thing:
if isinstance(thing, Comment):
format = strings.gold_summary_gilding_page_comment
desc = thing.body
else:
format = strings.gold_summary_gilding_page_link
desc = thing.markdown_link_slow()
elif signed:
format = strings.gold_summary_signed_gift
else:
@@ -2298,7 +2320,8 @@ class GoldPayment(Templated):
summary=summary, giftmessage=giftmessage,
pay_from_creddits=pay_from_creddits,
passthrough=passthrough,
comment=comment, clone_template=clone_template,
thing=thing, clone_template=clone_template,
description=desc, thing_type=thing_type,
paypal_buttonid=paypal_buttonid,
stripe_key=stripe_key,
coinbase_button_id=coinbase_button_id)
@@ -2340,7 +2363,7 @@ class GoldSubscription(Templated):
Templated.__init__(self)
class CreditGild(Templated):
"""Page for credit card payments for comment gilding."""
"""Page for credit card payments for gilding."""
pass

View File

@@ -37,7 +37,8 @@ class PrintableButtons(Styled):
show_delete = False, show_report = True,
show_distinguish = False, show_marknsfw = False,
show_unmarknsfw = False, is_link=False,
show_flair = False, show_rescrape=False, **kw):
show_flair=False, show_rescrape=False,
show_givegold=False, **kw):
show_ignore = thing.show_reports
approval_checkmark = getattr(thing, "approval_checkmark", None)
show_approve = (thing.show_spam or show_ignore or
@@ -59,6 +60,7 @@ class PrintableButtons(Styled):
show_unmarknsfw = show_unmarknsfw,
show_flair = show_flair,
show_rescrape=show_rescrape,
show_givegold=show_givegold,
**kw)
class BanButtons(PrintableButtons):
@@ -88,6 +90,7 @@ class LinkButtons(PrintableButtons):
if (not thing.is_self and
not (thing.has_thumbnail or thing.media_object)):
show_rescrape = True
show_givegold = thing.can_gild and (c.permalink_page or c.profilepage)
# do we show the delete button?
show_delete = is_author and delete and not thing._deleted
@@ -133,6 +136,7 @@ class LinkButtons(PrintableButtons):
show_unmarknsfw = show_unmarknsfw,
show_flair = thing.can_flair,
show_rescrape=show_rescrape,
show_givegold=show_givegold,
show_comments = comments,
# promotion
promoted = thing.promoted,
@@ -148,28 +152,13 @@ class CommentButtons(PrintableButtons):
# do we show the delete button?
show_delete = is_author and delete and not thing._deleted
can_gild = (
# you can't gild your own comment
not is_author
# no point in showing the button for things you've already gilded
and not thing.user_gilded
# this is a way of checking if the user is logged in that works
# both within CommentPane instances and without. e.g. CommentPane
# explicitly sets user_is_loggedin = False but can_reply is
# correct. while on user overviews, you can't reply but will get
# the correct value for user_is_loggedin
and (c.user_is_loggedin or thing.can_reply)
# ick, if the author deleted their account we shouldn't waste gold
and not thing.author._deleted
# some subreddits can have gilding disabled
and thing.subreddit.allow_comment_gilding
)
show_distinguish = (is_author and
(thing.can_ban or # Moderator distinguish
c.user.employee or # Admin distinguish
c.user_special_distinguish))
show_givegold = thing.can_gild
PrintableButtons.__init__(self, "commentbuttons", thing,
is_author = is_author,
profilepage = c.profilepage,
@@ -182,10 +171,11 @@ class CommentButtons(PrintableButtons):
deleted = thing.deleted,
parent_permalink = thing.parent_permalink,
can_reply = thing.can_reply,
can_gild=can_gild,
show_report = show_report,
show_distinguish = show_distinguish,
show_delete = show_delete)
show_delete = show_delete,
show_givegold=show_givegold,
)
class MessageButtons(PrintableButtons):
def __init__(self, thing, delete = False, report = True):

View File

@@ -144,15 +144,18 @@ string_dict = dict(
over_comment_limit_gold = _("Sorry, the maximum number of comments is %d."),
youve_got_gold = _("%(sender)s just gifted you %(amount)s of reddit gold!"),
giftgold_note = _("Here's a note that was included:\n\n----\n\n"),
youve_got_comment_gold = _("Another user liked [your comment](%(url)s) so much that they gilded it, giving you reddit gold.\n\n"),
youve_been_gilded_comment = _("Another user liked [your comment](%(url)s) so much that they gilded it, giving you reddit gold.\n\n"),
youve_been_gilded_link = _("Another user liked [your submission](%(url)s) so much that they gilded it, giving you reddit gold.\n\n"),
gold_summary_autorenew = _("You're about to set up an ongoing, autorenewing subscription to reddit gold for yourself (%(user)s)."),
gold_summary_onetime = _("You're about to make a one-time purchase of %(amount)s of reddit gold for yourself (%(user)s)."),
gold_summary_creddits = _("You're about to purchase %(amount)s of reddit gold creddits. They work like gift certificates: each creddit you have will allow you to give one month of reddit gold to someone else."),
gold_summary_gift_code = _("You're about to purchase %(amount)s of reddit gold in the form of a gift code. The recipient (or you) will be able to claim the code to redeem that gold to their account."),
gold_summary_signed_gift = _("You're about to give %(amount)s of reddit gold to %(recipient)s, who will be told that it came from you."),
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_summary_gilding_comment = _("Want to say thanks to *%(recipient)s* for this comment? Give them a month of [reddit gold](/gold/about)."),
gold_summary_gilding_link = _("Want to say thanks to *%(recipient)s* for this submission? Give them a month of [reddit gold](/gold/about)."),
gold_summary_gilding_page_comment = _("Give *%(recipient)s* a month of [reddit gold](/gold/about) for this comment:"),
gold_summary_gilding_page_link = _("Give *%(recipient)s* a month of [reddit gold](/gold/about) for this submission:"),
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."),

View File

@@ -22,12 +22,15 @@
from r2.lib.db.tdb_sql import make_metadata, index_str, create_table
import json
import pytz
import uuid
from pycassa import NotFoundException
from pycassa.system_manager import INT_TYPE, UTF8_TYPE
from pycassa.util import convert_uuid_to_time
from pylons import g, c
from pylons.i18n import _
from pylons.i18n import _, ungettext
from datetime import datetime
import sqlalchemy as sa
from sqlalchemy.exc import IntegrityError, OperationalError
@@ -42,7 +45,7 @@ from random import choice
from time import time
from r2.lib.db import tdb_cassandra
from r2.lib.db.tdb_cassandra import NotFound
from r2.lib.db.tdb_cassandra import NotFound, view_of
from r2.models import Account
from r2.models.subreddit import Frontpage
from r2.models.wiki import WikiPage
@@ -127,6 +130,107 @@ class GoldRevenueGoalByDate(object):
return None
class GildedCommentsByAccount(tdb_cassandra.DenormalizedRelation):
_use_db = True
_last_modified_name = 'Gilding'
_views = []
@classmethod
def value_for(cls, thing1, thing2):
return ''
@classmethod
def gild(cls, user, thing):
cls.create(user, [thing])
class GildedLinksByAccount(tdb_cassandra.DenormalizedRelation):
_use_db = True
_last_modified_name = 'Gilding'
_views = []
@classmethod
def value_for(cls, thing1, thing2):
return ''
@classmethod
def gild(cls, user, thing):
cls.create(user, [thing])
@view_of(GildedCommentsByAccount)
@view_of(GildedLinksByAccount)
class GildingsByThing(tdb_cassandra.View):
_use_db = True
_extra_schema_creation_args = {
"key_validation_class": tdb_cassandra.UTF8_TYPE,
"column_name_class": tdb_cassandra.UTF8_TYPE,
}
@classmethod
def get_gilder_ids(cls, thing):
columns = cls.get_time_sorted_columns(thing._fullname)
return [int(account_id, 36) for account_id in columns.iterkeys()]
@classmethod
def create(cls, user, things):
for thing in things:
cls._set_values(thing._fullname, {user._id36: ""})
@classmethod
def delete(cls, user, things):
# gildings cannot be undone
raise NotImplementedError()
@view_of(GildedCommentsByAccount)
@view_of(GildedLinksByAccount)
class GildingsByDay(tdb_cassandra.View):
_use_db = True
_compare_with = tdb_cassandra.TIME_UUID_TYPE
_extra_schema_creation_args = {
"key_validation_class": tdb_cassandra.ASCII_TYPE,
"column_name_class": tdb_cassandra.TIME_UUID_TYPE,
"default_validation_class": tdb_cassandra.UTF8_TYPE,
}
@staticmethod
def _rowkey(date):
return date.strftime("%Y-%m-%d")
@classmethod
def get_gildings(cls, date):
key = cls._rowkey(date)
columns = cls.get_time_sorted_columns(key)
gildings = []
for name, json_blob in columns.iteritems():
timestamp = convert_uuid_to_time(name)
date = datetime.utcfromtimestamp(timestamp).replace(tzinfo=g.tz)
gilding = json.loads(json_blob)
gilding["date"] = date
gilding["user"] = int(gilding["user"], 36)
gildings.append(gilding)
return gildings
@classmethod
def create(cls, user, things):
key = cls._rowkey(datetime.now(g.tz))
columns = {}
for thing in things:
columns[uuid.uuid1()] = json.dumps({
"user": user._id36,
"thing": thing._fullname,
})
cls._set_values(key, columns)
@classmethod
def delete(cls, user, things):
# gildings cannot be undone
raise NotImplementedError()
def create_unclaimed_gold (trans_id, payer_email, paying_id,
pennies, days, secret, date,
subscr_id = None):
@@ -404,3 +508,73 @@ def get_discounted_price(gold_price):
discount = float(getattr(g, 'BTC_DISCOUNT', '0'))
price = (gold_price.pennies * (1 - discount)) / 100.
return GoldPrice("%.2f" % price)
def make_gold_message(thing, user_gilded):
from r2.models import Comment
if thing.gildings == 0 or thing._spam or thing._deleted:
return None
author = Account._byID(thing.author_id, data=True)
if not author._deleted:
author_name = author.name
else:
author_name = _("[deleted]")
if c.user_is_loggedin and thing.author_id == c.user._id:
if isinstance(thing, Comment):
gilded_message = ungettext(
"a redditor gifted you a month of reddit gold for this "
"comment.",
"redditors have gifted you %(months)d months of reddit gold "
"for this comment.",
thing.gildings
)
else:
gilded_message = ungettext(
"a redditor gifted you a month of reddit gold for this "
"submission.",
"redditors have gifted you %(months)d months of reddit gold "
"for this submission.",
thing.gildings
)
elif user_gilded:
if isinstance(thing, Comment):
gilded_message = ungettext(
"you have gifted reddit gold to %(recipient)s for this "
"comment.",
"you and other redditors have gifted %(months)d months of "
"reddit gold to %(recipient)s for this comment.",
thing.gildings
)
else:
gilded_message = ungettext(
"you have gifted reddit gold to %(recipient)s for this "
"submission.",
"you and other redditors have gifted %(months)d months of "
"reddit gold to %(recipient)s for this submission.",
thing.gildings
)
else:
if isinstance(thing, Comment):
gilded_message = ungettext(
"a redditor has gifted reddit gold to %(recipient)s for this "
"comment.",
"redditors have gifted %(months)d months of reddit gold to "
"%(recipient)s for this comment.",
thing.gildings
)
else:
gilded_message = ungettext(
"a redditor has gifted reddit gold to %(recipient)s for this "
"submission.",
"redditors have gifted %(months)d months of reddit gold to "
"%(recipient)s for this submission.",
thing.gildings
)
return gilded_message % dict(
recipient=author_name,
months=thing.gildings,
)

View File

@@ -45,26 +45,28 @@ from r2.lib.strings import strings, Score
from r2.lib.db import tdb_cassandra
from r2.lib.db.tdb_cassandra import NotFoundException, view_of
from r2.lib.utils import sanitize_url
from r2.models.gold import (
GildedCommentsByAccount,
GildedLinksByAccount,
make_gold_message,
)
from r2.models.subreddit import MultiReddit
from r2.models.query_cache import CachedQueryMutator
from r2.models.promo import PROMOTE_STATUS, get_promote_srid
from pylons import c, g, request
from pylons.i18n import ungettext, _
from pylons.i18n import _
from datetime import datetime, timedelta
from hashlib import md5
from pycassa.util import convert_uuid_to_time
import random, re
import json
import uuid
class LinkExists(Exception): pass
# defining types
class Link(Thing, Printable):
_data_int_props = Thing._data_int_props + (
'num_comments', 'reported', 'comment_tree_id')
'num_comments', 'reported', 'comment_tree_id', 'gildings')
_defaults = dict(is_self=False,
over_18=False,
over_18_override=False,
@@ -87,6 +89,7 @@ class Link(Thing, Printable):
contest_mode=False,
skip_commentstree_q="",
ignore_reports=False,
gildings=0,
)
_essentials = ('sr_id', 'author_id')
_nsfw = re.compile(r"\bnsfw\b", re.I)
@@ -299,6 +302,28 @@ class Link(Thing, Printable):
return self.make_permalink(self.subreddit_slow,
force_domain=force_domain)
def markdown_link_slow(self):
return "[%s](%s)" % (self.title.decode('utf-8'),
self.make_permalink_slow())
def _gild(self, user):
now = datetime.now(g.tz)
self._incr("gildings")
GildedLinksByAccount.gild(user, self)
from r2.lib.db import queries
with CachedQueryMutator() as m:
gilding = utils.Storage(thing=self, date=now)
m.insert(queries.get_all_gilded_links(), [gilding])
m.insert(queries.get_gilded_links(self.sr_id), [gilding])
m.insert(queries.get_gilded_user_links(self.author_id),
[gilding])
m.insert(queries.get_user_gildings(user), [gilding])
hooks.get_hook('link.gild').call(link=self, gilder=user)
@staticmethod
def _should_expunge_selftext(link):
verdict = getattr(link, "verdict", "")
@@ -347,6 +372,13 @@ class Link(Thing, Printable):
for ban in bans_for_domain_parts(urls)}
if user_is_loggedin:
gilded = [thing for thing in wrapped if thing.gildings > 0]
try:
user_gildings = GildedLinksByAccount.fast_query(user, gilded)
except tdb_cassandra.TRANSIENT_EXCEPTIONS as e:
g.log.warning("Cassandra gilding lookup failed: %r", e)
user_gildings = {}
try:
saved = LinkSavesByAccount.fast_query(user, wrapped)
hidden = LinkHidesByAccount.fast_query(user, wrapped)
@@ -421,13 +453,29 @@ class Link(Thing, Printable):
item.urlprefix = ''
if user_is_loggedin:
item.user_gilded = (user, item) in user_gildings
item.saved = (user, item) in saved
item.hidden = (user, item) in hidden
item.visited = (user, item) in visited
else:
item.user_gilded = False
item.saved = item.hidden = item.visited = False
item.gilded_message = make_gold_message(item, item.user_gilded)
item.can_gild = (
c.user_is_loggedin and
# you can't gild your own submission
not (item.author and
item.author._id == user._id) and
# no point in showing the button for things you've already gilded
not item.user_gilded and
# ick, if the author deleted their account we shouldn't waste gold
not item.author._deleted and
# some subreddits can have gilding disabled
item.subreddit.allow_gilding
)
item.num = None
item.permalink = item.make_permalink(item.subreddit)
if item.is_self:
@@ -700,45 +748,6 @@ class PromotedLink(Link):
Printable.add_props(user, wrapped)
def make_comment_gold_message(comment, user_gilded):
if comment.gildings == 0 or comment._spam or comment._deleted:
return None
author = Account._byID(comment.author_id, data=True)
if not author._deleted:
author_name = author.name
else:
author_name = _("[deleted]")
if c.user_is_loggedin and comment.author_id == c.user._id:
gilded_message = ungettext(
"a redditor gifted you a month of reddit gold for this comment.",
"redditors have gifted you %(months)d months of reddit gold for "
"this comment.",
comment.gildings
)
elif user_gilded:
gilded_message = ungettext(
"you have gifted reddit gold to %(recipient)s for this comment.",
"you and other redditors have gifted %(months)d months of "
"reddit gold to %(recipient)s for this comment.",
comment.gildings
)
else:
gilded_message = ungettext(
"a redditor has gifted reddit gold to %(recipient)s for this "
"comment.",
"redditors have gifted %(months)d months of reddit gold to "
"%(recipient)s for this comment.",
comment.gildings
)
return gilded_message % dict(
recipient=author_name,
months=comment.gildings,
)
class Comment(Thing, Printable):
_data_int_props = Thing._data_int_props + ('reported', 'gildings')
_defaults = dict(reported=0,
@@ -882,7 +891,7 @@ class Comment(Thing, Printable):
self._incr("gildings")
GildedCommentsByAccount.gild_comment(user, self)
GildedCommentsByAccount.gild(user, self)
from r2.lib.db import queries
with CachedQueryMutator() as m:
@@ -976,10 +985,9 @@ class Comment(Thing, Printable):
now = datetime.now(g.tz)
if user_is_loggedin:
gilded = [comment for comment in wrapped if comment.gildings > 0]
gilded = [thing for thing in wrapped if thing.gildings > 0]
try:
user_gildings = GildedCommentsByAccount.fast_query(user,
gilded)
user_gildings = GildedCommentsByAccount.fast_query(user, gilded)
except tdb_cassandra.TRANSIENT_EXCEPTIONS as e:
g.log.warning("Cassandra gilding lookup failed: %r", e)
user_gildings = {}
@@ -1038,8 +1046,26 @@ class Comment(Thing, Printable):
else:
item.user_gilded = False
item.saved = False
item.gilded_message = make_comment_gold_message(item,
item.user_gilded)
item.gilded_message = make_gold_message(item, item.user_gilded)
item.can_gild = (
# this is a way of checking if the user is logged in that works
# both within CommentPane instances and without. e.g. CommentPane
# explicitly sets user_is_loggedin = False but can_reply is
# correct. while on user overviews, you can't reply but will get
# the correct value for user_is_loggedin
(c.user_is_loggedin or getattr(item, "can_reply", True)) and
# you can't gild your own comment
not (c.user_is_loggedin and
item.author and
item.author._id == user._id) and
# no point in showing the button for things you've already gilded
not item.user_gilded and
# ick, if the author deleted their account we shouldn't waste gold
not item.author._deleted and
# some subreddits can have gilding disabled
item.subreddit.allow_gilding
)
# not deleted on profile pages,
# deleted if spam and not author or admin
@@ -1537,91 +1563,6 @@ class Message(Thing, Printable):
return True
class GildedCommentsByAccount(tdb_cassandra.DenormalizedRelation):
_use_db = True
_last_modified_name = 'Gilding'
_views = []
@classmethod
def value_for(cls, thing1, thing2):
return ''
@classmethod
def gild_comment(cls, user, comment):
cls.create(user, [comment])
@view_of(GildedCommentsByAccount)
class GildingsByThing(tdb_cassandra.View):
_use_db = True
_extra_schema_creation_args = {
"key_validation_class": tdb_cassandra.UTF8_TYPE,
"column_name_class": tdb_cassandra.UTF8_TYPE,
}
@classmethod
def get_gilder_ids(cls, thing):
columns = cls.get_time_sorted_columns(thing._fullname)
return [int(account_id, 36) for account_id in columns.iterkeys()]
@classmethod
def create(cls, user, things):
for thing in things:
cls._set_values(thing._fullname, {user._id36: ""})
@classmethod
def delete(cls, user, things):
# gildings cannot be undone
raise NotImplementedError()
@view_of(GildedCommentsByAccount)
class GildingsByDay(tdb_cassandra.View):
_use_db = True
_compare_with = tdb_cassandra.TIME_UUID_TYPE
_extra_schema_creation_args = {
"key_validation_class": tdb_cassandra.ASCII_TYPE,
"column_name_class": tdb_cassandra.TIME_UUID_TYPE,
"default_validation_class": tdb_cassandra.UTF8_TYPE,
}
@staticmethod
def _rowkey(date):
return date.strftime("%Y-%m-%d")
@classmethod
def get_gildings(cls, date):
key = cls._rowkey(date)
columns = cls.get_time_sorted_columns(key)
gildings = []
for name, json_blob in columns.iteritems():
timestamp = convert_uuid_to_time(name)
date = datetime.utcfromtimestamp(timestamp).replace(tzinfo=g.tz)
gilding = json.loads(json_blob)
gilding["date"] = date
gilding["user"] = int(gilding["user"], 36)
gildings.append(gilding)
return gildings
@classmethod
def create(cls, user, things):
key = cls._rowkey(datetime.now(g.tz))
columns = {}
for thing in things:
columns[uuid.uuid1()] = json.dumps({
"user": user._id36,
"thing": thing._fullname,
})
cls._set_values(key, columns)
@classmethod
def delete(cls, user, things):
# gildings cannot be undone
raise NotImplementedError()
class _SaveHideByAccount(tdb_cassandra.DenormalizedRelation):
@classmethod
def value_for(cls, thing1, thing2):

View File

@@ -141,9 +141,9 @@ class BaseSite(object):
from r2.lib.db import queries
return queries.get_sr_comments(self)
def get_gilded_comments(self):
def get_gilded(self):
from r2.lib.db import queries
return queries.get_gilded_comments(self)
return queries.get_gilded(self._id)
@classmethod
def get_modactions(cls, srs, mod=None, action=None):
@@ -205,7 +205,7 @@ class Subreddit(Thing, Printable, BaseSite):
prev_description_id="",
prev_submit_text_id="",
prev_public_description_id="",
allow_comment_gilding=True,
allow_gilding=True,
hide_subscribers=False,
public_traffic=False,
spam_links='high',
@@ -929,7 +929,7 @@ class FakeSubreddit(BaseSite):
from r2.lib.db import queries
return queries.get_all_comments()
def get_gilded_comments(self):
def get_gilded(self):
raise NotImplementedError()
def spammy(self):
@@ -1006,19 +1006,16 @@ class FriendsSR(FakeSubreddit):
for friend in friends]
return queries.MergedCachedResults(crs)
def get_gilded_comments(self):
from r2.lib.db.queries import get_gilded_user_comments
def get_gilded(self):
from r2.lib.db.queries import get_gilded_users
if not c.user_is_loggedin:
raise UserRequiredException
friends = self.get_important_friends(c.user._id)
if not friends:
return []
queries = [get_gilded_user_comments(user_id) for user_id in friends]
return MergedCachedQuery(queries)
return get_gilded_users(friends)
class AllSR(FakeSubreddit):
@@ -1047,9 +1044,9 @@ class AllSR(FakeSubreddit):
from r2.lib.db import queries
return queries.get_all_comments()
def get_gilded_comments(self):
def get_gilded(self):
from r2.lib.db import queries
return queries.get_all_gilded_comments()
return queries.get_all_gilded()
class AllMinus(AllSR):
@@ -1196,11 +1193,9 @@ class DefaultSR(_DefaultSR):
results = [get_sr_comments(sr) for sr in srs]
return merge_results(*results)
def get_gilded_comments(self):
from r2.lib.db.queries import get_gilded_comments
srs = Subreddit.user_subreddits(c.user)
queries = [get_gilded_comments(sr_id) for sr_id in srs]
return MergedCachedQuery(queries)
def get_gilded(self):
from r2.lib.db.queries import get_gilded
return get_gilded(Subreddit.user_subreddits(c.user))
class MultiReddit(FakeSubreddit):
@@ -1267,10 +1262,9 @@ class MultiReddit(FakeSubreddit):
results = [get_sr_comments(sr) for sr in srs]
return merge_results(*results)
def get_gilded_comments(self):
from r2.lib.db.queries import get_gilded_comments
queries = [get_gilded_comments(sr_id) for sr_id in self.kept_sr_ids]
return MergedCachedQuery(queries)
def get_gilded(self):
from r2.lib.db.queries import get_gilded
return get_gilded(self.kept_sr_ids)
class TooManySubredditsError(Exception):

View File

@@ -303,14 +303,14 @@ body[orient="landscape"] > #topbar > h1 { margin-left: -125px; width: 250px; }
.comment.collapsed .tagline { margin-left: 20px; font-style: italcs; color: #AAA; }
/** comment gilding */
.gilded-comment-icon { position: relative; display: inline-block; margin: 0 0 -15px 8px; top: -8px; color: #99895F; font-size: .9em; vertical-align: middle; }
/** gilding */
.gilded-icon { position: relative; display: inline-block; margin: 0 0 -15px 8px; top: -8px; color: #99895F; font-size: .9em; vertical-align: middle; }
.gilded-comment-icon:before { display: inline-block; content: ''; background-image: url(../gold-coin.png); /* SPRITE */ background-repeat: no-repeat; height: 14px; width: 13px; margin-right: 2px; vertical-align: -3px; }
.gilded-icon:before { display: inline-block; content: ''; background-image: url(../gold-coin.png); /* SPRITE */ background-repeat: no-repeat; height: 14px; width: 13px; margin-right: 2px; vertical-align: -3px; }
.user-gilded > .entry .gilded-comment-icon:before { width: 23px; }
.user-gilded > .entry .gilded-icon:before { width: 23px; }
body.post-under-6h-old .gilded-comment-icon { opacity: .55; }
body.post-under-6h-old .gilded-icon { opacity: .55; }
/** messages and inbox */
.message { background: white; position: relative; border: 1px solid #d9d9d9; margin: 10px; -webkit-border-radius: 8px; -moz-border-radius: 8px; -ms-border-radius: 8px; -o-border-radius: 8px; border-radius: 8px; padding: 5px; }

View File

@@ -887,8 +887,8 @@ padding: 5px;
}
/** comment gilding */
.gilded-comment-icon {
/** gilding */
.gilded-icon {
position: relative;
display: inline-block;
margin: 0 0 -15px 8px;
@@ -898,7 +898,7 @@ padding: 5px;
vertical-align: middle;
}
.gilded-comment-icon:before {
.gilded-icon:before {
display: inline-block;
content: '';
background-image: url(../gold-coin.png); /* SPRITE */
@@ -909,11 +909,11 @@ padding: 5px;
vertical-align: -3px;
}
.user-gilded > .entry .gilded-comment-icon:before {
.user-gilded > .entry .gilded-icon:before {
width: 23px;
}
body.post-under-6h-old .gilded-comment-icon {
body.post-under-6h-old .gilded-icon {
opacity: .55;
}

View File

@@ -42,12 +42,12 @@
clear: both;
}
.gilded-comment-icon {
.gilded-icon {
background: url(gold-coin.png) no-repeat;
padding-left: 15px;
height: 14px;
}
.user-gilded > .entry .gilded-comment-icon {
.user-gilded > .entry .gilded-icon {
padding-left: 25px;
}

View File

@@ -6018,7 +6018,7 @@ dd { margin-left: 20px; }
.icon-menu .reddit-contributors:before,
.icon-menu .reddit-modqueue:before,
.giftgold a:before,
.gilded-comments-link a:before,
.gilded-link a:before,
.infobar.gold:before,
.gold-form h1.goldgift:before,
.users-online:before,
@@ -6350,17 +6350,17 @@ body:not(.gold) .allminus-link {
font-size: 1.15em;
}
.gilded-comments-link {
.gilded-link {
margin-top: 1em;
}
.gilded-comments-link a {
.gilded-link a {
color: #9a7d2e;
font-weight: bold;
font-size: 1.15em;
}
.gilded-comments-link a:before {
.gilded-link a:before {
height: 14px;
width: 14px;
margin: 0 6px 0 1px;
@@ -6544,7 +6544,7 @@ body:not(.gold) .allminus-link {
position: absolute;
}
.gold-form.cloneable {
.gold-form.cloneable-link, .gold-form.cloneable-comment {
display: none;
}
@@ -6572,8 +6572,8 @@ body:not(.gold) .allminus-link {
margin: 5px 0;
}
.comment .gold-form {
margin: 0 0 10px 4px;
.thing .gold-form {
margin: 10px 0 10px 4px;
min-height: 0;
}
@@ -7588,7 +7588,7 @@ table.diff {font-size: small;}
.diff_chg {background-color:yellow}
.diff_sub {background-color:lightcoral}
.gilded-comment-icon {
.gilded-icon {
position: relative;
display: inline-block;
margin: 0 0 -15px 8px;
@@ -7598,7 +7598,7 @@ table.diff {font-size: small;}
vertical-align: middle;
}
.gilded-comment-icon:before {
.gilded-icon:before {
display: inline-block;
content: '';
background-image: url(../gold-coin.png); /* SPRITE */
@@ -7609,11 +7609,11 @@ table.diff {font-size: small;}
vertical-align: -3px;
}
.user-gilded > .entry .gilded-comment-icon:before {
.user-gilded > .entry .gilded-icon:before {
width: 23px;
}
body.post-under-6h-old .gilded-comment-icon {
body.post-under-6h-old .gilded-icon {
opacity: .55;
}

View File

@@ -5,7 +5,7 @@ r.gold = {
$('div.content').on(
'click',
'a.give-gold, .gold-payment .close-button',
$.proxy(this, '_toggleCommentGoldForm')
$.proxy(this, '_toggleThingGoldForm')
)
$('.stripe-gold').click(function(){
@@ -21,11 +21,11 @@ r.gold = {
})
},
_toggleCommentGoldForm: function (e) {
_toggleThingGoldForm: function (e) {
var $link = $(e.target),
$thing = $link.thing(),
commentId = $link.thing_id(),
formId = 'gold_form_' + commentId,
thingFullname = $link.thing_id(),
formId = 'gold_form_' + thingFullname,
oldForm = $('#' + formId)
if ($thing.hasClass('user-gilded') ||
@@ -47,12 +47,18 @@ r.gold = {
this._googleCheckoutAnalyticsLoaded = true
}
var form = $('.gold-form.cloneable:first').clone(),
if ($thing.hasClass('link')) {
var cloneClass = 'cloneable-link'
} else {
var cloneClass = 'cloneable-comment'
}
var form = $('.gold-form.' + cloneClass + ':first').clone(),
authorName = $link.thing().find('.entry .author:first').text(),
passthroughs = form.find('.passthrough'),
cbBaseUrl = form.find('[name="cbbaseurl"]').val()
form.removeClass('cloneable')
form.removeClass(cloneClass)
.attr('id', formId)
.find('p:first-child em').text(authorName).end()
.find('button').attr('disabled', '')
@@ -66,7 +72,7 @@ r.gold = {
form.find('button').addClass('disabled')
}, 200)
$.request('generate_payment_blob.json', {comment: commentId}, function (token) {
$.request('generate_payment_blob.json', {thing: thingFullname}, function (token) {
clearTimeout(workingTimer)
form.removeClass('working')
passthroughs.val(token)
@@ -78,18 +84,18 @@ r.gold = {
return false
},
gildComment: function (comment_id, new_title, specified_gilding_count) {
var comment = $('.id-' + comment_id)
gildThing: function (thing_fullname, new_title, specified_gilding_count) {
var thing = $('.id-' + thing_fullname)
if (!comment.length) {
console.log("couldn't gild comment " + comment_id)
if (!thing.length) {
console.log("couldn't gild thing " + thing_fullname)
return
}
var tagline = comment.children('.entry').find('p.tagline'),
icon = tagline.find('.gilded-comment-icon')
var tagline = thing.children('.entry').find('p.tagline'),
icon = tagline.find('.gilded-icon')
// when a comment is gilded interactively, we need to increment the
// when a thing is gilded interactively, we need to increment the
// gilding count displayed by the UI. however, when gildings are
// instantiated from a cached comment page via thingupdater, we can't
// simply increment the gilding count because we do not know if the
@@ -104,10 +110,10 @@ r.gold = {
gilding_count++
}
comment.addClass('gilded user-gilded')
thing.addClass('gilded user-gilded')
if (!icon.length) {
icon = $('<span>')
.addClass('gilded-comment-icon')
.addClass('gilded-icon')
tagline.append(icon)
}
icon
@@ -117,7 +123,7 @@ r.gold = {
icon.text('x' + gilding_count)
}
comment.children('.entry').find('.give-gold').parent().remove()
thing.children('.entry').find('.give-gold').parent().remove()
},
tokenThenPost: function (dest) {
@@ -199,8 +205,8 @@ r.gold = {
};
(function($) {
$.gild_comment = function (comment_id, new_title) {
r.gold.gildComment(comment_id, new_title)
$('#gold_form_' + comment_id).fadeOut(400)
$.gild_thing = function (thing_fullname, new_title) {
r.gold.gildThing(thing_fullname, new_title)
$('#gold_form_' + thing_fullname).fadeOut(400)
}
})(jQuery)

View File

@@ -39,7 +39,7 @@
%endif
%if not thing.gilding_listing:
<div class="gilded-comments-link">
<a href="/r/all/comments/gilded">${_("See gilded comments")}</a>
<div class="gilded-link">
<a href="/r/all/gilded">${_("See gilded comments and submissions")}</a>
</div>
%endif

View File

@@ -70,7 +70,7 @@
## thing.timesince is a cache stub
${unsafe(_("%(timeago)s ago") % dict(timeago=thing.timesince))}
% if thing.gilded_message:
<span class="gilded-comment-icon" title="${thing.gilded_message}" data-count="${thing.gildings}">
<span class="gilded-icon" title="${thing.gilded_message}" data-count="${thing.gildings}">
% if thing.gildings > 1:
x${thing.gildings}
% endif

View File

@@ -124,15 +124,7 @@ ${parent.collapsed()}
${edited(thing, thing.lastedited)}
%endif
% if thing.gilded_message:
<a href="${thing.subreddit_path}gilded">
<span class="gilded-comment-icon" title="${thing.gilded_message}" data-count="${thing.gildings}">
% if thing.gildings > 1:
x${thing.gildings}
% endif
</span>
</a>
% endif
${self.gildings()}
%if collapse:
&nbsp;<a href="#" class="expand"

View File

@@ -33,7 +33,7 @@
<div class="roundfield-content">
${unsafe(safemarkdown(thing.summary, wrap=False))}
<div class="giftmessage">
${unsafe(safemarkdown(thing.comment.body))}
${unsafe(safemarkdown(thing.description))}
</div>
${stripe_form(display=True)}
</div>

View File

@@ -25,9 +25,16 @@
<%
from r2.lib.filters import unsafe, safemarkdown
from r2.lib.template_helpers import static
clone_class = ''
if thing.clone_template:
if thing.thing_type == 'comment':
clone_class = 'cloneable-comment'
else:
clone_class = 'cloneable-link'
%>
<div class="gold-form gold-payment ${'cloneable' if thing.clone_template else ''}">
<div class="gold-form gold-payment ${clone_class}">
<div class="roundfield">
% if thing.clone_template:
<button class="close-button">${_('close')}</button>
@@ -35,9 +42,9 @@
<img src="${static('reddit_gold-70.png')}" class="gold-logo">
<div class="roundfield-content">
${unsafe(safemarkdown(thing.summary, wrap=False))}
%if thing.comment and not thing.clone_template:
%if thing.thing and not thing.clone_template:
<div class="giftmessage">
${unsafe(safemarkdown(thing.comment.body))}
${unsafe(safemarkdown(thing.description))}
</div>
%endif

View File

@@ -216,6 +216,9 @@ ${parent.thing_data_attributes(what)} data-ups="${what.upvotes}" data-downs="${w
author=WrappedUser(thing.author, thing.attribs, thing).render(),
lastedited=capture(edited, thing, thing.lastedited)
))}
%if c.permalink_page or c.profilepage:
${self.gildings()}
%endif
%if thing.stickied:
&#32;-&#32;<span class="stickied-tagline" title="selected by this subreddit's moderators">stickied post</span>
%endif

View File

@@ -54,6 +54,18 @@ ${self.RenderPrintable()}
%endif
</%def>
<%def name="gildings()">
% if thing.gilded_message:
<a href="${thing.subreddit_path}gilded">
<span class="gilded-icon" title="${thing.gilded_message}" data-count="${thing.gildings}">
% if thing.gildings > 1:
x${thing.gildings}
% endif
</span>
</a>
% endif
</%def>
<%def name="thing_css_class(what)">
<%
cssclass = "thing"

View File

@@ -122,6 +122,17 @@
%endif
</%def>
<%def name="give_gold()">
% if thing.show_givegold:
<li>
<a href="/gold?goldtype=gift&months=1&thing=${thing.thing._fullname}"
title="${_("give reddit gold in appreciation of this post.")}"
class="give-gold login-required"
>${_("give gold")}</a>
</li>
% endif
</%def>
<%def name="ignore_reports_toggle(thing)">
<%
label = _("ignore reports")
@@ -202,6 +213,7 @@
%endif
${self.distinguish()}
${self.give_gold()}
${self.banbuttons()}
%if thing.promoted is not None:
%if thing.user_is_sponsor or thing.is_author:
@@ -295,14 +307,7 @@
%endif
${self.banbuttons()}
${self.distinguish()}
% if thing.can_gild:
<li>
<a href="/gold?goldtype=gift&months=1&comment=${thing.thing._fullname}"
title="${_("give reddit gold in appreciation of this comment.")}"
class="give-gold login-required"
>${_("give gold")}</a>
</li>
% endif
${self.give_gold()}
%if not thing.profilepage and thing.can_reply:
<li>
${self.simple_button(_("reply {verb}"), "reply")}

View File

@@ -37,9 +37,9 @@
$.map(friends, show_friend);
var gildings = ${unsafe(simplejson.dumps(thing.gildings))};
for (var gilded_comment in gildings) {
var gilding_data = gildings[gilded_comment];
r.gold.gildComment(gilded_comment, gilding_data[0], gilding_data[1]);
for (var gilded_thing in gildings) {
var gilding_data = gildings[gilded_thing];
r.gold.gildThing(gilded_thing, gilding_data[0], gilding_data[1]);
}
var saves = ${unsafe(simplejson.dumps(list(thing.saves)))};