Permalink
Fetching contributors…
Cannot retrieve contributors at this time
153 lines (124 sloc) 5.6 KB
# 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 __future__ import with_statement
from r2.lib.db.thing import MultiRelation, Relation, thing_prefix, cache
from r2.lib.utils import tup, timeago
from r2.lib.db.operators import ip_network
from r2.lib.normalized_hot import expire_hot
from r2.config.databases import tz
from account import Account
from link import Link, Comment
from subreddit import Subreddit
from datetime import timedelta, datetime
from pylons import g, c
def score_changes(amount, old_amount):
uc = dc = 0
a, oa = amount, old_amount
if oa == 0 and a > 0: uc = a
elif oa == 0 and a < 0: dc = -a
elif oa > 0 and a == 0: uc = -oa
elif oa < 0 and a == 0: dc = oa
elif oa > 0 and a < 0: uc = -oa; dc = -a
elif oa < 0 and a > 0: dc = oa; uc = a
return uc, dc
class Vote(MultiRelation('vote',
Relation(Account, Link),
Relation(Account, Comment))):
@classmethod
def vote(cls, sub, obj, dir, ip, spam = False, organic = False):
from admintools import valid_user, valid_thing, update_score
from r2.lib.count import incr_counts
# An account can only perform 1 voting operation at a time.
with g.make_lock('account_%s_voting' % sub._id) as lock:
kind = obj.__class__.__name__.lower()
lock.log('voting checkpoint A')
# If downvoting ensure that the user has enough karma, it
# will raise an exception if not.
if dir == False:
sub.check_downvote(kind)
lock.log('voting checkpoint B')
# Do the voting.
sr = obj.subreddit_slow
karma = sub.karma(kind, sr)
lock.log('voting checkpoint C')
#check for old vote
rel = cls.rel(sub, obj)
oldvote = list(rel._query(rel.c._thing1_id == sub._id,
rel.c._thing2_id == obj._id,
data = True))
amount = 1 if dir is True else 0 if dir is None else -1
# Users have a vote_multiplier which effects how much their votes are worth
if isinstance(sub, Account):
amount *= sub.vote_multiplier
lock.log('voting checkpoint D')
is_new = False
#old vote
if len(oldvote):
v = oldvote[0]
oldamount = int(v._name)
v._name = str(amount)
#these still need to be recalculated
old_valid_thing = getattr(v, 'valid_thing', True)
v.valid_thing = (valid_thing(v, karma)
and v.valid_thing
and not spam)
v.valid_user = (v.valid_user
and v.valid_thing
and valid_user(v, sr, karma))
#new vote
else:
is_new = True
oldamount = 0
v = rel(sub, obj, str(amount))
v.author_id = obj.author_id
v.ip = ip
old_valid_thing = v.valid_thing = (valid_thing(v, karma) and
not spam)
v.valid_user = v.valid_thing and valid_user(v, sr, karma)
if organic:
v.organic = organic
lock.log('voting checkpoint E')
v._commit()
lock.log('voting checkpoint F')
# Record that this account has made a downvote.
up_change, down_change = score_changes(amount, oldamount)
if down_change:
sub.incr_downvote(down_change, kind)
lock.log('voting checkpoint G')
# Release the lock since both the downvote count and the vote count
# have been updated, and then continue by updating karmas.
update_score(obj, up_change, down_change,
v.valid_thing, old_valid_thing)
if v.valid_user:
author = Account._byID(obj.author_id, data=True)
author.incr_karma(kind, sr, up_change, down_change)
#update the sr's valid vote count
if is_new and v.valid_thing and kind == 'link':
if sub._id != obj.author_id:
incr_counts([sr])
return v
#TODO make this generic and put on multirelation?
@classmethod
def likes(cls, sub, obj):
votes = cls._fast_query(sub, obj, None, data=False)
votes = dict((tuple(k[:2]), v) for k, v in votes.iteritems() if v)
return votes