mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-27 03:00:12 -04:00
Remove the quota system
This commit is contained in:
@@ -387,8 +387,6 @@ MIN_RATE_LIMIT_COMMENT_KARMA = 1
|
||||
|
||||
|
||||
############################################ THRESHOLDS
|
||||
# minimum item score to be considered for quota baskets
|
||||
QUOTA_THRESHOLD = 5
|
||||
# if the user has positive total karma, their per-subreddit karma will default to this, else 0
|
||||
MIN_UP_KARMA = 1
|
||||
|
||||
|
||||
@@ -497,34 +497,6 @@ class ApiController(RedditController):
|
||||
if form.has_errors('ratelimit', errors.RATELIMIT):
|
||||
return
|
||||
|
||||
filled_quota = c.user.quota_full('link')
|
||||
if filled_quota is not None:
|
||||
if c.user._spam:
|
||||
msg = strings.generic_quota_msg
|
||||
else:
|
||||
log_text ("over-quota",
|
||||
"%s just went over their per-%s quota" %
|
||||
(c.user.name, filled_quota), "info")
|
||||
|
||||
verify_link = "/verify?reason=submit"
|
||||
reddiquette_link = "/wiki/reddiquette"
|
||||
|
||||
if c.user.email_verified:
|
||||
msg = strings.verified_quota_msg
|
||||
msg %= {"reddiquette": reddiquette_link}
|
||||
else:
|
||||
msg = strings.unverified_quota_msg
|
||||
msg %= {
|
||||
"verify": verify_link,
|
||||
"reddiquette": reddiquette_link,
|
||||
}
|
||||
|
||||
md = safemarkdown(msg)
|
||||
form.set_html(".status", md)
|
||||
c.errors.add(errors.QUOTA_FILLED)
|
||||
form.set_error(errors.QUOTA_FILLED, None)
|
||||
return
|
||||
|
||||
if kind == 'link':
|
||||
if not url or form.has_errors("url", errors.NO_URL, errors.BAD_URL):
|
||||
return
|
||||
@@ -585,7 +557,6 @@ class ApiController(RedditController):
|
||||
cheater=c.cheater)
|
||||
|
||||
if sr.should_ratelimit(c.user, 'link'):
|
||||
c.user.clog_quota('link', l)
|
||||
VRatelimit.ratelimit(rate_user=True, rate_ip = True,
|
||||
prefix = "rate_submit_")
|
||||
|
||||
|
||||
@@ -172,7 +172,6 @@ class Globals(object):
|
||||
'MIN_RATE_LIMIT_KARMA',
|
||||
'MIN_RATE_LIMIT_COMMENT_KARMA',
|
||||
'HOT_PAGE_AGE',
|
||||
'QUOTA_THRESHOLD',
|
||||
'ADMIN_COOKIE_TTL',
|
||||
'ADMIN_COOKIE_MAX_IDLE',
|
||||
'OTP_COOKIE_TTL',
|
||||
|
||||
@@ -81,7 +81,6 @@ error_list = dict((
|
||||
('INVALID_TARGET', _('that target type is not valid')),
|
||||
('INVALID_OS_VERSION', _('that version range is not valid')),
|
||||
('RATELIMIT', _('you are doing that too much. try again in %(time)s.')),
|
||||
('QUOTA_FILLED', _("You've submitted too many links recently. Please try again in an hour.")),
|
||||
('SUBREDDIT_RATELIMIT', _("you are doing that too much. try again later.")),
|
||||
('EXPIRED', _('your session has expired')),
|
||||
('DRACONIAN', _('you must accept the terms first')),
|
||||
|
||||
@@ -117,9 +117,6 @@ string_dict = dict(
|
||||
completely_invalid_search_query = _("I couldn't understand your search query. Please try again."),
|
||||
search_help = _("You may also want to check the [search help page](%(search_help)s) for more information."),
|
||||
formatting_help_info = _('reddit uses a slightly-customized version of [Markdown](http://daringfireball.net/projects/markdown/syntax) for formatting. See below for some basics, or check [the commenting wiki page](/wiki/commenting) for more detailed help and solutions to common issues.'),
|
||||
generic_quota_msg = _("You've submitted too many links recently. Please try again in an hour."),
|
||||
verified_quota_msg = _("Looks like you're either a brand new user or your posts have not been doing well recently. You may have to wait a bit to post again. In the meantime feel free to [check out the reddiquette](%(reddiquette)s) or join the conversation in a different thread."),
|
||||
unverified_quota_msg = _("Looks like you're either a brand new user or your posts have not been doing well recently. You may have to wait a bit to post again. In the meantime feel free to [check out the reddiquette](%(reddiquette)s), join the conversation in a different thread, or [verify your email address](%(verify)s)."),
|
||||
read_only_msg = _("Reddit is in \"emergency read-only mode\" right now. :( You won't be able to log in. We're sorry and are working frantically to fix the problem."),
|
||||
heavy_load_msg = _("this page is temporarily in read-only mode due to heavy traffic."),
|
||||
gold_benefits_msg = _("reddit gold is reddit's premium membership program. Here are the benefits:\n\n* [Extra site features](/gold/about)\n* [Extra perks](/gold/partners)\n* Discuss and get help on the features and perks at /r/goldbenefits"),
|
||||
|
||||
@@ -46,7 +46,6 @@ from datetime import datetime, timedelta
|
||||
import bcrypt
|
||||
import hmac
|
||||
import hashlib
|
||||
import itertools
|
||||
from pycassa.system_manager import ASCII_TYPE
|
||||
|
||||
|
||||
@@ -532,121 +531,15 @@ class Account(Thing):
|
||||
else:
|
||||
return None
|
||||
|
||||
def quota_key(self, kind):
|
||||
return "user_%s_quotas-%s" % (kind, self.name)
|
||||
|
||||
def clog_quota(self, kind, item):
|
||||
key = self.quota_key(kind)
|
||||
fnames = g.hardcache.get(key, [])
|
||||
fnames.append(item._fullname)
|
||||
g.hardcache.set(key, fnames, 86400 * 30)
|
||||
|
||||
def quota_baskets(self, kind):
|
||||
from r2.models.admintools import filter_quotas
|
||||
key = self.quota_key(kind)
|
||||
fnames = g.hardcache.get(key)
|
||||
|
||||
if not fnames:
|
||||
return None
|
||||
|
||||
unfiltered = Thing._by_fullname(fnames, data=True, return_dict=False)
|
||||
|
||||
baskets, new_quotas = filter_quotas(unfiltered)
|
||||
|
||||
if new_quotas is None:
|
||||
pass
|
||||
elif new_quotas == []:
|
||||
g.hardcache.delete(key)
|
||||
else:
|
||||
g.hardcache.set(key, new_quotas, 86400 * 30)
|
||||
|
||||
return baskets
|
||||
|
||||
# Needs to take the *canonicalized* version of each email
|
||||
# When true, returns the reason
|
||||
@classmethod
|
||||
def which_emails_are_banned(cls, canons):
|
||||
banned = hooks.get_hook('email.get_banned').call(canons=canons)
|
||||
|
||||
# Create a dictionary like:
|
||||
# d["abc.def.com"] = [ "bob@abc.def.com", "sue@abc.def.com" ]
|
||||
rv = {}
|
||||
canons_by_domain = {}
|
||||
|
||||
# email.get_banned will return a list of lists (one layer from the
|
||||
# hooks system, the second from the function itself); chain them
|
||||
# together for easy processing
|
||||
for canon in itertools.chain(*banned):
|
||||
rv[canon] = None
|
||||
|
||||
at_sign = canon.find("@")
|
||||
domain = canon[at_sign+1:]
|
||||
canons_by_domain.setdefault(domain, [])
|
||||
canons_by_domain[domain].append(canon)
|
||||
|
||||
# Hand off to the domain ban system; it knows in the case of
|
||||
# abc@foo.bar.com to check foo.bar.com, bar.com, and .com
|
||||
from r2.models.admintools import bans_for_domain_parts
|
||||
|
||||
for domain, canons in canons_by_domain.iteritems():
|
||||
for d in bans_for_domain_parts(domain):
|
||||
if d.no_email:
|
||||
rv[canon] = "domain"
|
||||
|
||||
return rv
|
||||
|
||||
def set_email(self, email):
|
||||
old_email = self.email
|
||||
self.email = email
|
||||
self._commit()
|
||||
AccountsByCanonicalEmail.update_email(self, old_email, email)
|
||||
|
||||
def has_banned_email(self):
|
||||
canon = self.canonical_email()
|
||||
which = self.which_emails_are_banned((canon,))
|
||||
return which.get(canon, None)
|
||||
|
||||
def canonical_email(self):
|
||||
return canonicalize_email(self.email)
|
||||
|
||||
def cromulent(self):
|
||||
"""Return whether the user has validated their email address and
|
||||
passes some rudimentary 'not evil' checks."""
|
||||
|
||||
if not self.email_verified:
|
||||
return False
|
||||
|
||||
if self.has_banned_email():
|
||||
return False
|
||||
|
||||
# Otherwise, congratulations; you're cromulent!
|
||||
return True
|
||||
|
||||
def quota_limits(self, kind):
|
||||
if kind != 'link':
|
||||
raise NotImplementedError
|
||||
|
||||
if self.cromulent():
|
||||
return dict(hour=3, day=10, week=50, month=150)
|
||||
else:
|
||||
return dict(hour=1, day=3, week=5, month=5)
|
||||
|
||||
def quota_full(self, kind):
|
||||
limits = self.quota_limits(kind)
|
||||
baskets = self.quota_baskets(kind)
|
||||
|
||||
if baskets is None:
|
||||
return None
|
||||
|
||||
total = 0
|
||||
filled_quota = None
|
||||
for key in ('hour', 'day', 'week', 'month'):
|
||||
total += len(baskets[key])
|
||||
if total >= limits[key]:
|
||||
filled_quota = key
|
||||
|
||||
return filled_quota
|
||||
|
||||
@classmethod
|
||||
def system_user(cls):
|
||||
try:
|
||||
|
||||
@@ -363,60 +363,6 @@ def ip_span(ip):
|
||||
ip = websafe(ip)
|
||||
return '<!-- %s -->' % ip
|
||||
|
||||
def filter_quotas(unfiltered):
|
||||
now = datetime.now(g.tz)
|
||||
|
||||
baskets = {
|
||||
'hour': [],
|
||||
'day': [],
|
||||
'week': [],
|
||||
'month': [],
|
||||
}
|
||||
|
||||
new_quotas = []
|
||||
quotas_changed = False
|
||||
|
||||
for item in unfiltered:
|
||||
delta = now - item._date
|
||||
|
||||
age = delta.days * 86400 + delta.seconds
|
||||
|
||||
# First, select a basket or abort if item is too old
|
||||
if age < 3600:
|
||||
basket = 'hour'
|
||||
elif age < 86400:
|
||||
basket = 'day'
|
||||
elif age < 7 * 86400:
|
||||
basket = 'week'
|
||||
elif age < 30 * 86400:
|
||||
basket = 'month'
|
||||
else:
|
||||
quotas_changed = True
|
||||
continue
|
||||
|
||||
verdict = getattr(item, "verdict", None)
|
||||
approved = verdict and verdict in (
|
||||
'admin-approved', 'mod-approved')
|
||||
|
||||
# Then, make sure it's worthy of quota-clogging
|
||||
if item._spam:
|
||||
pass
|
||||
elif item._score <= 0:
|
||||
pass
|
||||
elif age < 86400 and item._score <= g.QUOTA_THRESHOLD and not approved:
|
||||
pass
|
||||
else:
|
||||
quotas_changed = True
|
||||
continue
|
||||
|
||||
baskets[basket].append(item)
|
||||
new_quotas.append(item._fullname)
|
||||
|
||||
if quotas_changed:
|
||||
return baskets, new_quotas
|
||||
else:
|
||||
return baskets, None
|
||||
|
||||
|
||||
def wiki_template(template_slug, sr=None):
|
||||
"""Pull content from a subreddit's wiki page for internal use."""
|
||||
|
||||
Reference in New Issue
Block a user