mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-27 03:00:12 -04:00
* Add a new Cassandra CF for comment-sort caching * Add JSONP support * Support non-auto-renewing PayPal IPNs * Gold accounting * Gold features: comments tracking, larger comment limit * Autorenewing gold * Google checkout support * Profile-page sorting for all * Title-text on the logo * Hardcache sharding and profiling * Self serve enhancements * Add /r/foo/faq * Make self-centred reddits allow for more verbose selftext * Much better down-handling of databases * Add the ability to take a thread-dump from a running process * Remove the comscore tracker * Add comments to modqueue (does not back-populate)
177 lines
6.2 KiB
Python
177 lines
6.2 KiB
Python
# 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 CondeNet, Inc.
|
|
#
|
|
# All portions of the code written by CondeNet are Copyright (c) 2006-2008
|
|
# CondeNet, Inc. All Rights Reserved.
|
|
################################################################################
|
|
from r2.lib.db.thing import Thing, Relation, NotFound
|
|
from r2.lib.db.userrel import UserRel
|
|
from r2.lib.db.operators import asc, desc, lower
|
|
from r2.lib.memoize import memoize
|
|
from r2.models import Account
|
|
from pylons import c, g, request
|
|
|
|
class Award (Thing):
|
|
_defaults = dict(
|
|
awardtype = 'regular',
|
|
)
|
|
|
|
@classmethod
|
|
@memoize('award.all_awards')
|
|
def _all_awards_cache(cls):
|
|
return [ a._id for a in Award._query(sort=asc('_date'), limit=100) ]
|
|
|
|
@classmethod
|
|
def _all_awards(cls, _update=False):
|
|
all = Award._all_awards_cache(_update=_update)
|
|
# Can't just return Award._byID() results because
|
|
# the ordering will be lost
|
|
d = Award._byID(all, data=True)
|
|
return [ d[id] for id in all ]
|
|
|
|
@classmethod
|
|
def _new(cls, codename, title, awardtype, imgurl):
|
|
# print "Creating new award codename=%s title=%s imgurl=%s" % (
|
|
# codename, title, imgurl)
|
|
a = Award(codename=codename, title=title, awardtype=awardtype,
|
|
imgurl=imgurl)
|
|
a._commit()
|
|
Award._all_awards_cache(_update=True)
|
|
|
|
@classmethod
|
|
def _by_codename(cls, codename):
|
|
q = cls._query(lower(Award.c.codename) == codename.lower())
|
|
q._limit = 1
|
|
award = list(q)
|
|
|
|
if award:
|
|
return cls._byID(award[0]._id, True)
|
|
else:
|
|
raise NotFound, 'Award %s' % codename
|
|
|
|
@classmethod
|
|
def give_if_needed(cls, codename, user,
|
|
description=None, url=None, cup_info=None):
|
|
"""Give an award to a user, unless they already have it.
|
|
Returns the trophy. Does nothing and prints nothing
|
|
(except for g.log.debug) if the award doesn't exist."""
|
|
|
|
try:
|
|
award = Award._by_codename(codename)
|
|
except NotFound:
|
|
g.log.debug("No award named '%s'" % codename)
|
|
return None
|
|
|
|
trophies = Trophy.by_account(user)
|
|
|
|
for trophy in trophies:
|
|
if trophy._thing2.codename == codename:
|
|
g.log.debug("%s already has %s" % (user, codename))
|
|
return trophy
|
|
|
|
g.log.debug("Gave %s to %s" % (codename, user))
|
|
return Trophy._new(user, award, description=description,
|
|
url=url, cup_info=cup_info)
|
|
|
|
@classmethod
|
|
def take_away(cls, codename, user):
|
|
"""Takes an award out of a user's trophy case. Returns silently
|
|
(except for g.log.debug) if there's no such award."""
|
|
|
|
found = False
|
|
|
|
try:
|
|
award = Award._by_codename(codename)
|
|
except NotFound:
|
|
g.log.debug("No award named '%s'" % codename)
|
|
return
|
|
|
|
trophies = Trophy.by_account(user)
|
|
|
|
for trophy in trophies:
|
|
if trophy._thing2.codename == codename:
|
|
if found:
|
|
g.log.debug("%s had multiple %s awards!" % (user, codename))
|
|
trophy._delete()
|
|
Trophy.by_account(user, _update=True)
|
|
Trophy.by_award(award, _update=True)
|
|
found = True
|
|
|
|
if found:
|
|
g.log.debug("Took %s from %s" % (codename, user))
|
|
else:
|
|
g.log.debug("%s didn't have %s" % (user, codename))
|
|
|
|
class Trophy(Relation(Account, Award)):
|
|
@classmethod
|
|
def _new(cls, recipient, award, description = None,
|
|
url = None, cup_info = None):
|
|
|
|
# The "name" column of the relation can't be a constant or else a
|
|
# given account would not be allowed to win a given award more than
|
|
# once. So we're setting it to the string form of the timestamp.
|
|
# Still, we won't have that date just yet, so for a moment we're
|
|
# setting it to "trophy".
|
|
|
|
t = Trophy(recipient, award, "trophy")
|
|
|
|
t._name = str(t._date)
|
|
|
|
if description:
|
|
t.description = description
|
|
|
|
if url:
|
|
t.url = url
|
|
|
|
if cup_info:
|
|
recipient.set_cup(cup_info)
|
|
|
|
t._commit()
|
|
Trophy.by_account(recipient, _update=True)
|
|
Trophy.by_award(award, _update=True)
|
|
|
|
@classmethod
|
|
@memoize('trophy.by_account2')
|
|
def by_account_cache(cls, account_id):
|
|
q = Trophy._query(Trophy.c._thing1_id == account_id,
|
|
sort = desc('_date'))
|
|
q._limit = 500
|
|
return [ t._id for t in q ]
|
|
|
|
@classmethod
|
|
def by_account(cls, account, _update=False):
|
|
rel_ids = cls.by_account_cache(account._id, _update=_update)
|
|
trophies = Trophy._byID_rel(rel_ids, data=True, eager_load=True,
|
|
thing_data=True, return_dict = False)
|
|
return trophies
|
|
|
|
@classmethod
|
|
@memoize('trophy.by_award2')
|
|
def by_award_cache(cls, award_id):
|
|
q = Trophy._query(Trophy.c._thing2_id == award_id,
|
|
sort = desc('_date'))
|
|
q._limit = 500
|
|
return [ t._id for t in q ]
|
|
|
|
@classmethod
|
|
def by_award(cls, award, _update=False):
|
|
rel_ids = cls.by_award_cache(award._id, _update=_update)
|
|
trophies = Trophy._byID_rel(rel_ids, data=True, eager_load=True,
|
|
thing_data=True, return_dict = False)
|
|
return trophies
|