mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-27 03:00:12 -04:00
* Activate negative-result caching for HardCache chain
* begin migration to pylibmc:
* Add pylibmc to the list of required packages in preparation for the replacement of the memcached library
* Start using pylibmc for the rendercaches
* Tweak the computation of the normalized hot page to be a bit faster when the precomputer is available, by relying on the precomputer's internal permacached structure.
* Default to a SelfEmptyingCache for scripts run from `paster run'. Note that processes that run forever are still responsible for resetting their local-caches, but this can now be done with g.reset_caches()
* threaded messaging patch part 1: backend changes only. This will allow migrate.py to be run to move new onto inbox and will start tracking message trees for users.
* Specify some queries to run at most once per day
* Refactored safemarkdown() and added soup testing
Additions:
* Added _byID_rel()
* Made error messages more verbose for:
1. byID lookups of too-big thing_ids
2. memcache failures
3. Solr Nones
* Award._all_awards() now sorts by date
* Trophy.by_{account,award}() now cache properly
* new feedback page with helpful links
* Try to reduce the length of the query-queue by not adding known-long queries at all, rather than adding them and skipping them
* whitespace clean up
* simplify the 'why did my CC get denied' email checking.
* added missing translation strings and users now get PMs when they are added as translators
Bugfixes:
* Fix a bug in unsaving
* BeautifulSoup stopped hosting 3.0.7a, but 3.0.8 still uses the good parser
* Better search error handling
* Properly reset the cache-chains (incl. the hardcache; d'oh!) per-request
* Fix an attribute error on listings where some items have author_ids and some don't
* Bug when forcing recalculation of memoized functions
* the subreddit creation and edit form aren't dealing with errors properly
* buttons fix
188 lines
6.8 KiB
Python
188 lines
6.8 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-2010
|
|
# CondeNet, Inc. All Rights Reserved.
|
|
################################################################################
|
|
from pylons import request, g
|
|
from reddit_base import RedditController
|
|
from r2.lib.pages import UnfoundPage, AdminTranslations, \
|
|
AdminPage, Translator_Message
|
|
|
|
from r2.lib.translation import Translator, TranslatorTemplate, get_translator
|
|
from validator import *
|
|
from gettext import _translations
|
|
|
|
from r2.lib.wrapped import Wrapped
|
|
|
|
class VTranslator(Validator):
|
|
def run(self, lang):
|
|
if (not c.user_is_admin and
|
|
(not c.user_is_loggedin or not lang or
|
|
c.user.name not in Translator.get_author(lang))):
|
|
abort(404, 'page not found')
|
|
|
|
class VTranslationEnabled(Validator):
|
|
def run(self):
|
|
if not g.translator:
|
|
abort(403, 'forbidden')
|
|
|
|
|
|
class I18nController(RedditController):
|
|
|
|
@validate(VTranslationEnabled(),
|
|
VAdmin(),
|
|
lang = nop('lang'),
|
|
a = VExistingUname('name'))
|
|
def POST_adduser(self, lang, a):
|
|
from r2.lib.db import queries
|
|
if a and Translator.exists(lang):
|
|
tr = get_translator(locale = lang)
|
|
tr.author.add(a.name)
|
|
tr.save()
|
|
|
|
# send the user a message
|
|
body = Translator_Message(lang, a).render("html")
|
|
subject = "Thanks for offering to help translate!"
|
|
m, inbox_rel = Message._new(c.user, a, subject, body, request.ip)
|
|
queries.new_message(m, inbox_rel)
|
|
|
|
return self.redirect("/admin/i18n")
|
|
|
|
|
|
@validate(VTranslationEnabled(),
|
|
VAdmin())
|
|
def GET_list(self):
|
|
res = AdminPage(content = AdminTranslations(),
|
|
title = 'translate reddit',
|
|
show_sidebar = False).render()
|
|
return res
|
|
|
|
|
|
@validate(VTranslationEnabled(),
|
|
VAdmin(),
|
|
lang = nop('name'))
|
|
def POST_new(self, lang):
|
|
if lang and not Translator.exists(lang):
|
|
tr = get_translator(locale = lang)
|
|
tr.save()
|
|
return self.redirect("/admin/i18n")
|
|
|
|
|
|
@validate(VTranslationEnabled(),
|
|
VTranslator('lang'),
|
|
lang = nop('lang'))
|
|
def GET_edit(self, lang):
|
|
if not lang and c.user_is_admin:
|
|
content = Wrapped(TranslatorTemplate())
|
|
elif Translator.exists(lang):
|
|
content = Wrapped(get_translator(locale = lang))
|
|
else:
|
|
content = UnfoundPage()
|
|
res = AdminPage(content = content,
|
|
title = 'translate reddit',
|
|
show_sidebar = False).render()
|
|
return res
|
|
|
|
@validate(VTranslationEnabled(),
|
|
VTranslator('lang'),
|
|
lang = nop('lang'),
|
|
numbers = VBoolean("numbers"))
|
|
def GET_try(self, lang, numbers):
|
|
if lang:
|
|
tr = get_translator(locale = lang)
|
|
tr.save(compile=True, include_index = numbers)
|
|
|
|
tran_keys = _translations.keys()
|
|
for key in tran_keys:
|
|
if key.endswith(tr._out_file('mo')):
|
|
del _translations[key]
|
|
|
|
return self.redirect("http://%s.%s/" %
|
|
(lang, g.domain))
|
|
return abort(404, 'page not found')
|
|
|
|
@validate(VTranslationEnabled(),
|
|
VTranslator('lang'),
|
|
post = nop('post'),
|
|
try_trans = nop('try'),
|
|
lang = nop('lang'))
|
|
def POST_edit(self, lang, post, try_trans):
|
|
if (lang and not Translator.exists(lang)):
|
|
return self.redirect('/admin/i18n')
|
|
|
|
if lang:
|
|
tr = get_translator(locale = lang)
|
|
else:
|
|
tr = TranslatorTemplate()
|
|
|
|
enabled = set()
|
|
for k, val in request.post.iteritems():
|
|
if k.startswith('trans_'):
|
|
k = k.split('_')
|
|
val = val.replace('\n', ' ').replace('\r', ' ')
|
|
# check if this is a translation string
|
|
if k[1:] and tr.get(k[1]):
|
|
tr.set(k[1], val, indx = int(k[2] if k[2:] else -1))
|
|
# check if this is an admin editing the source/comment lines
|
|
elif c.user_is_admin and tr.sources.get(k[1]):
|
|
source = tr.sources.get(k[1])
|
|
tr.source_trans[source] = val
|
|
elif c.user_is_admin and k.startswith('enabled_'):
|
|
k = k.split('_')
|
|
enabled.add(k[1])
|
|
|
|
# update the enabled state of the buttons
|
|
if c.user_is_admin and enabled:
|
|
strings = set(tr.string_dict.keys())
|
|
disabled = strings - enabled
|
|
for s in strings:
|
|
tr.set_enabled(s, True)
|
|
for s in disabled:
|
|
tr.set_enabled(s, False)
|
|
|
|
if request.post.get('nplurals'):
|
|
try:
|
|
tr.plural_names = [request.post.get('pluralform_%d' % i) \
|
|
for i in xrange(tr.nplurals)]
|
|
tr.nplurals = int(request.post.get('nplurals'))
|
|
except ValueError:
|
|
pass
|
|
if request.post.get('langname'):
|
|
tr.name = request.post['langname']
|
|
if request.post.get('enlangname'):
|
|
tr.en_name = request.post['enlangname']
|
|
|
|
tr.save(compile=bool(try_trans))
|
|
|
|
if try_trans:
|
|
tran_keys = _translations.keys()
|
|
for key in tran_keys:
|
|
if key.endswith(tr._out_file('mo')):
|
|
del _translations[key]
|
|
|
|
return self.redirect("http://%s/?lang=%s" %
|
|
(g.domain, lang))
|
|
|
|
whereto = request.post.get('bttn_num', '')
|
|
if whereto:
|
|
whereto = 'bttn_num_%s' % whereto
|
|
return self.redirect("/admin/i18n/edit/%s#%s" % (lang or '', whereto))
|
|
return res
|
|
|