Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Round 2 of import updates

* Added @export decorator
* Fixed @memoize and @wraps_api to use functools @wraps to ensure __name__ and
  __module__ are preserved
* refactored a few files to handle cycles
* added test_imports.py to allow 'compiling' all the python files and ensure
  they
* r2.config up to import snuff
* r2.controllers up to import snuff
* removed large import blocks and replaced with use of <module>.<symbol> style
* Fixed a lot of kw args with a key = value style to use key=value (only fixed
  where other change was needed)
* Started work on r2.lib, but not finished yet
  • Loading branch information...
commit 25155c2f4bf41fba56aad2a65e63592f5a1db90f 1 parent 235f5b7
@kkress authored
Showing with 3,255 additions and 2,704 deletions.
  1. +5 −0 r2/r2/config/environment.py
  2. +17 −0 r2/r2/config/extensions.py
  3. +8 −4 r2/r2/config/middleware.py
  4. +6 −0 r2/r2/config/rewrites.py
  5. +1 −2  r2/r2/config/routing.py
  6. +27 −27 r2/r2/config/templates.py
  7. +52 −38 r2/r2/controllers/__init__.py
  8. +14 −9 r2/r2/controllers/ads.py
  9. +610 −659 r2/r2/controllers/api.py
  10. +14 −3 r2/r2/controllers/api_docs.py
  11. +5 −0 r2/r2/controllers/apiv1.py
  12. +24 −26 r2/r2/controllers/awards.py
  13. +36 −40 r2/r2/controllers/buttons.py
  14. +5 −0 r2/r2/controllers/captcha.py
  15. +5 −0 r2/r2/controllers/embed.py
  16. +5 −0 r2/r2/controllers/error.py
  17. +13 −7 r2/r2/controllers/errorlog.py
  18. +5 −0 r2/r2/controllers/errors.py
  19. +12 −7 r2/r2/controllers/feedback.py
  20. +377 −442 r2/r2/controllers/front.py
  21. +5 −0 r2/r2/controllers/health.py
  22. +26 −26 r2/r2/controllers/ipn.py
  23. +125 −153 r2/r2/controllers/listingcontroller.py
  24. +5 −1 r2/r2/controllers/mediaembed.py
  25. +45 −37 r2/r2/controllers/oauth2.py
  26. +59 −56 r2/r2/controllers/post.py
  27. +136 −152 r2/r2/controllers/promotecontroller.py
  28. +5 −1 r2/r2/controllers/querycontroller.py
  29. +48 −65 r2/r2/controllers/reddit_base.py
  30. +5 −0 r2/r2/controllers/redirect.py
  31. +10 −3 r2/r2/controllers/toolbar.py
  32. +187 −1 r2/r2/controllers/validator/validator.py
  33. +20 −9 r2/r2/lib/amqp.py
  34. +61 −43 r2/r2/lib/app_globals.py
  35. +3 −1 r2/r2/lib/authentication.py
  36. +1 −0  r2/r2/lib/authorize/__init__.py
  37. +11 −7 r2/r2/lib/authorize/api.py
  38. +5 −2 r2/r2/lib/authorize/interaction.py
  39. +23 −7 r2/r2/lib/cloudsearch.py
  40. +1 −1  r2/r2/lib/cssfilter.py
  41. +41 −0 r2/r2/lib/export.py
  42. +12 −8 r2/r2/lib/jsonresponse.py
  43. +2 −1  r2/r2/lib/memoize.py
  44. +13 −6 r2/r2/lib/menus.py
  45. +6 −5 r2/r2/lib/mr_account.py
  46. +3 −1 r2/r2/lib/pages/__init__.py
  47. +16 −3 r2/r2/lib/pages/admin_pages.py
  48. +439 −291 r2/r2/lib/pages/pages.py
  49. +9 −40 r2/r2/lib/pages/things.py
  50. +11 −7 r2/r2/lib/pages/trafficpages.py
  51. +2 −2 r2/r2/lib/wrapped.pyx
  52. +76 −0 r2/r2/lib/wrapper.py
  53. +35 −23 r2/r2/models/account.py
  54. +3 −5 r2/r2/models/account_subreddit.py
  55. +9 −2 r2/r2/models/ad.py
  56. +38 −25 r2/r2/models/admintools.py
  57. +5 −8 r2/r2/models/award.py
  58. +76 −80 r2/r2/models/bidding.py
  59. +8 −10 r2/r2/models/builder.py
  60. +22 −16 r2/r2/models/builders.py
  61. +6 −9 r2/r2/models/flair.py
  62. +52 −50 r2/r2/models/gold.py
  63. +6 −8 r2/r2/models/jury.py
  64. +4 −5 r2/r2/models/keyvalue.py
  65. +3 −5 r2/r2/models/last_modified.py
  66. +37 −26 r2/r2/models/link.py
  67. +11 −9 r2/r2/models/listing.py
  68. +109 −110 r2/r2/models/mail_queue.py
  69. +3 −7 r2/r2/models/modaction.py
  70. +4 −2 r2/r2/models/populatedb.py
  71. +3 −5 r2/r2/models/printable.py
  72. +4 −5 r2/r2/models/promo.py
  73. +12 −14 r2/r2/models/query_cache.py
  74. +3 −7 r2/r2/models/report.py
  75. +37 −29 r2/r2/models/subreddit.py
  76. +10 −12 r2/r2/models/token.py
  77. +13 −16 r2/r2/models/traffic.py
  78. +3 −7 r2/r2/models/trial.py
  79. +17 −15 r2/r2/models/vote.py
  80. +69 −0 r2/r2/tests/functional/test_imports.py
  81. +1 −1  r2/r2/tests/test_models.py
View
5 r2/r2/config/environment.py
@@ -30,11 +30,16 @@
from r2.config import routing
from r2.lib.app_globals import Globals
from r2.lib.configparse import ConfigValue
+from r2.lib.export import export
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
mimetypes.init()
+@export
def load_environment(global_conf={}, app_conf={}, setup_globals=True):
# Setup our paths
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
View
17 r2/r2/config/extensions.py
@@ -22,16 +22,31 @@
from pylons import c
+from r2.lib.export import export
+
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ "API_TYPES",
+ "extension_mapping",
+ ]
+
+
+@export
def api_type(subtype = ''):
return 'api-' + subtype if subtype else 'api'
+
+@export
def is_api(subtype = ''):
return c.render_style and c.render_style.startswith(api_type(subtype))
+
+@export
def get_api_subtype():
if is_api() and c.render_style.startswith('api-'):
return c.render_style[4:]
+
extension_mapping = {
"rss": ("xml", "text/xml; charset=UTF-8"),
"xml": ("xml", "text/xml; charset=UTF-8"),
@@ -50,8 +65,10 @@ def get_api_subtype():
"i": ("compact", "text/html; charset=UTF-8"),
}
+
API_TYPES = ('api', 'json')
+@export
def set_extension(environ, ext):
environ["extension"] = ext
environ["render_style"], environ["content_type"] = extension_mapping[ext]
View
12 r2/r2/config/middleware.py
@@ -24,22 +24,26 @@
import re
import urllib
import tempfile
-import urlparse
from threading import Lock
from paste.cascade import Cascade
+from paste.deploy.converters import asbool
from paste.registry import RegistryManager
from paste.urlparser import StaticURLParser
-from paste.deploy.converters import asbool
from pylons import config, Response
from pylons.error import error_template
from pylons.middleware import ErrorDocuments, ErrorHandler, StaticJavascripts
from pylons.wsgiapp import PylonsApp, PylonsBaseWSGIApp
+from r2.lib.utils import is_subdomain
+
from r2.config.environment import load_environment
-from r2.config.rewrites import rewrites
from r2.config.extensions import extension_mapping, set_extension
-from r2.lib.utils import is_subdomain
+from r2.config.rewrites import rewrites
+
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
# hack in Paste support for HTTP 429 "Too Many Requests"
View
6 r2/r2/config/rewrites.py
@@ -22,6 +22,12 @@
import re
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ "rewrites",
+ ]
+
+
rewrites = (#these first two rules prevent the .embed rewrite from
#breaking other js that should work
("\A/_(.*)", "/_$1"),
View
3  r2/r2/config/routing.py
@@ -23,9 +23,8 @@
"""
Setup your Routes options here
"""
-import os
-from routes import Mapper
from pylons import config
+from routes import Mapper
def make_map():
map = Mapper()
View
54 r2/r2/config/templates.py
@@ -20,8 +20,8 @@
# Inc. All Rights Reserved.
###############################################################################
+import r2.lib.jsontemplates as jtmpl
from r2.lib.manager import tp_manager
-from r2.lib.jsontemplates import *
tpm = tp_manager.tp_manager()
@@ -31,35 +31,35 @@ def api(type, cls):
tpm.add_handler(type, 'api-compact', cls())
# blanket fallback rule
-api('templated', NullJsonTemplate)
+api('templated', jtmpl.NullJsonTemplate)
# class specific overrides
-api('link', LinkJsonTemplate)
-api('promotedlink', PromotedLinkJsonTemplate)
-api('comment', CommentJsonTemplate)
-api('message', MessageJsonTemplate)
-api('subreddit', SubredditJsonTemplate)
-api('morerecursion', MoreCommentJsonTemplate)
-api('morechildren', MoreCommentJsonTemplate)
-api('reddit', RedditJsonTemplate)
-api('panestack', PanestackJsonTemplate)
-api('listing', ListingJsonTemplate)
-api('modlist', UserListJsonTemplate)
-api('userlist', UserListJsonTemplate)
-api('contributorlist', UserListJsonTemplate)
-api('bannedlist', UserListJsonTemplate)
-api('friendlist', UserListJsonTemplate)
-api('usertableitem', UserTableItemJsonTemplate)
-api('account', AccountJsonTemplate)
+api('link', jtmpl.LinkJsonTemplate)
+api('promotedlink', jtmpl.PromotedLinkJsonTemplate)
+api('comment', jtmpl.CommentJsonTemplate)
+api('message', jtmpl.MessageJsonTemplate)
+api('subreddit', jtmpl.SubredditJsonTemplate)
+api('morerecursion', jtmpl.MoreCommentJsonTemplate)
+api('morechildren', jtmpl.MoreCommentJsonTemplate)
+api('reddit', jtmpl.RedditJsonTemplate)
+api('panestack', jtmpl.PanestackJsonTemplate)
+api('listing', jtmpl.ListingJsonTemplate)
+api('modlist', jtmpl.UserListJsonTemplate)
+api('userlist', jtmpl.UserListJsonTemplate)
+api('contributorlist', jtmpl.UserListJsonTemplate)
+api('bannedlist', jtmpl.UserListJsonTemplate)
+api('friendlist', jtmpl.UserListJsonTemplate)
+api('usertableitem', jtmpl.UserTableItemJsonTemplate)
+api('account', jtmpl.AccountJsonTemplate)
-api('organiclisting', OrganicListingJsonTemplate)
-api('subreddittraffic', TrafficJsonTemplate)
-api('takedownpane', TakedownJsonTemplate)
+api('organiclisting', jtmpl.OrganicListingJsonTemplate)
+api('subreddittraffic', jtmpl.TrafficJsonTemplate)
+api('takedownpane', jtmpl.TakedownJsonTemplate)
-api('flairlist', FlairListJsonTemplate)
-api('flaircsv', FlairCsvJsonTemplate)
+api('flairlist', jtmpl.FlairListJsonTemplate)
+api('flaircsv', jtmpl.FlairCsvJsonTemplate)
-api('subredditstylesheet', StylesheetTemplate)
-api('createsubreddit', SubredditSettingsTemplate)
+api('subredditstylesheet', jtmpl.StylesheetTemplate)
+api('createsubreddit', jtmpl.SubredditSettingsTemplate)
-tpm.add_handler('usertableitem', 'api-html', UserItemHTMLJsonTemplate())
+tpm.add_handler('usertableitem', 'api-html', jtmpl.UserItemHTMLJsonTemplate())
View
90 r2/r2/controllers/__init__.py
@@ -20,9 +20,18 @@
# Inc. All Rights Reserved.
###############################################################################
+from r2.lib.export import export
+
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
+
_reddit_controllers = {}
_plugin_controllers = {}
+
+@export
def get_controller(name):
name = name.lower() + 'controller'
if name in _reddit_controllers:
@@ -32,53 +41,58 @@ def get_controller(name):
else:
raise KeyError(name)
+
+@export
def add_controller(controller):
name = controller.__name__.lower()
assert name not in _plugin_controllers
_plugin_controllers[name] = controller
return controller
+
+@export
def load_controllers():
- from listingcontroller import ListingController
- from listingcontroller import HotController
- from listingcontroller import NewController
- from listingcontroller import BrowseController
- from listingcontroller import MessageController
- from listingcontroller import RedditsController
- from listingcontroller import ByIDController
- from listingcontroller import RandomrisingController
- from listingcontroller import UserController
- from listingcontroller import CommentsController
+ from r2.controllers.listingcontroller import ListingController
+ from r2.controllers.listingcontroller import HotController
+ from r2.controllers.listingcontroller import NewController
+ from r2.controllers.listingcontroller import BrowseController
+ from r2.controllers.listingcontroller import MessageController
+ from r2.controllers.listingcontroller import RedditsController
+ from r2.controllers.listingcontroller import ByIDController
+ from r2.controllers.listingcontroller import RandomrisingController
+ from r2.controllers.listingcontroller import UserController
+ from r2.controllers.listingcontroller import CommentsController
- from listingcontroller import MyredditsController
+ from r2.controllers.listingcontroller import MyredditsController
- from feedback import FeedbackController
- from front import FormsController
- from front import FrontController
- from health import HealthController
- from buttons import ButtonsController
- from captcha import CaptchaController
- from embed import EmbedController
- from error import ErrorController
- from post import PostController
- from toolbar import ToolbarController
- from awards import AwardsController
- from ads import AdsController
- from usage import UsageController
- from errorlog import ErrorlogController
- from promotecontroller import PromoteController
- from mediaembed import MediaembedController
- from mediaembed import AdController
+ from r2.controllers.feedback import FeedbackController
+ from r2.controllers.front import FormsController
+ from r2.controllers.front import FrontController
+ from r2.controllers.health import HealthController
+ from r2.controllers.buttons import ButtonsController
+ from r2.controllers.captcha import CaptchaController
+ from r2.controllers.embed import EmbedController
+ from r2.controllers.error import ErrorController
+ from r2.controllers.post import PostController
+ from r2.controllers.toolbar import ToolbarController
+ from r2.controllers.awards import AwardsController
+ from r2.controllers.ads import AdsController
+ from r2.controllers.usage import UsageController
+ from r2.controllers.errorlog import ErrorlogController
+ from r2.controllers.promotecontroller import PromoteController
+ from r2.controllers.mediaembed import MediaembedController
+ from r2.controllers.mediaembed import AdController
- from querycontroller import QueryController
+ from r2.controllers.querycontroller import QueryController
- from api import ApiController
- from api import ApiminimalController
- from api_docs import ApidocsController
- from apiv1 import APIv1Controller
- from oauth2 import OAuth2FrontendController
- from oauth2 import OAuth2AccessController
- from redirect import RedirectController
- from ipn import IpnController
+ from r2.controllers.api import ApiController
+ from r2.controllers.api import ApiminimalController
+ from r2.controllers.api_docs import ApidocsController
+ from r2.controllers.apiv1 import APIv1Controller
+ from r2.controllers.oauth2 import OAuth2FrontendController
+ from r2.controllers.oauth2 import OAuth2AccessController
+ from r2.controllers.redirect import RedirectController
+ from r2.controllers.ipn import IpnController
- _reddit_controllers.update((name.lower(), obj) for name, obj in locals().iteritems())
+ controllers = [(name.lower(), obj) for name, obj in locals().iteritems()]
+ _reddit_controllers.update(controllers)
View
23 r2/r2/controllers/ads.py
@@ -22,25 +22,30 @@
from pylons.controllers.util import abort
+from r2.lib.export import export
from r2.lib.pages import AdminPage, AdminAds, AdminAdAssign, AdminAdSRs
+import r2.controllers.validator as validator
from r2.controllers.reddit_base import RedditController
-from r2.controllers.validator import (VAdByCodename,
- VSponsorAdmin,
- validate,
- )
+from r2.controllers.validator import validate
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
+
+@export
class AdsController(RedditController):
- @validate(VSponsorAdmin())
+ @validate(validator.VSponsorAdmin())
def GET_index(self):
res = AdminPage(content = AdminAds(),
show_sidebar = False,
title = 'ads').render()
return res
- @validate(VSponsorAdmin(),
- ad = VAdByCodename('adcn'))
+ @validate(validator.VSponsorAdmin(),
+ ad = validator.VAdByCodename('adcn'))
def GET_assign(self, ad):
if ad is None:
abort(404, 'page not found')
@@ -50,8 +55,8 @@ def GET_assign(self, ad):
title='assign an ad to a community').render()
return res
- @validate(VSponsorAdmin(),
- ad = VAdByCodename('adcn'))
+ @validate(validator.VSponsorAdmin(),
+ ad = validator.VAdByCodename('adcn'))
def GET_srs(self, ad):
if ad is None:
abort(404, 'page not found')
View
1,269 r2/r2/controllers/api.py
610 additions, 659 deletions not shown
View
17 r2/r2/controllers/api_docs.py
@@ -21,16 +21,24 @@
###############################################################################
import re
+import inspect
from collections import defaultdict
from itertools import chain
-import inspect
from os.path import abspath, relpath
from pylons import g
from pylons.i18n import _
-from reddit_base import RedditController
-from r2.lib.utils import Storage
+
+from r2.lib.export import export
from r2.lib.pages import BoringPage, ApiHelp
+from r2.lib.utils import Storage
+
+from r2.controllers.reddit_base import RedditController
+
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
# API sections displayed in the documentation page.
# Each section can have a title and a markdown-formatted description.
@@ -72,6 +80,8 @@
api_section = Storage((k, k) for k in section_info)
+
+@export
def api_doc(section, **kwargs):
"""
Add documentation annotations to the decorated function.
@@ -94,6 +104,7 @@ def add_metadata(api_function):
return api_function
return add_metadata
+
class ApidocsController(RedditController):
@staticmethod
def docs_from_controller(controller, url_prefix='/api'):
View
5 r2/r2/controllers/apiv1.py
@@ -27,6 +27,11 @@
from r2.controllers.api_docs import api_doc, api_section
from r2.controllers.oauth2 import OAuth2ResourceController, require_oauth2_scope
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
+
class APIv1Controller(OAuth2ResourceController):
def try_pagecache(self):
pass
View
50 r2/r2/controllers/awards.py
@@ -22,48 +22,46 @@
from pylons import request, g
-from r2.lib.pages import (AdminPage,
- AdminAwards,
- AdminAwardGive,
- AdminAwardWinners,
- )
+from r2.lib import pages
+from r2.controllers import validator
from r2.controllers.reddit_base import RedditController
-from r2.controllers.validator import (VAdmin,
- VAwardByCodename,
- nop,
- validate,
- )
+from r2.controllers.validator import validate
+
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
class AwardsController(RedditController):
- @validate(VAdmin())
+ @validate(validator.VAdmin())
def GET_index(self):
- res = AdminPage(content = AdminAwards(),
- title = 'awards').render()
+ res = pages.AdminPage(content = pages.AdminAwards(),
+ title = 'awards').render()
return res
- @validate(VAdmin(),
- award = VAwardByCodename('awardcn'),
- recipient = nop('recipient'),
- desc = nop('desc'),
- url = nop('url'),
- hours = nop('hours'))
+ @validate(validator.VAdmin(),
+ award=validator.VAwardByCodename('awardcn'),
+ recipient=validator.nop('recipient'),
+ desc=validator.nop('desc'),
+ url=validator.nop('url'),
+ hours=validator.nop('hours'))
def GET_give(self, award, recipient, desc, url, hours):
if award is None:
abort(404, 'page not found')
- res = AdminPage(content = AdminAwardGive(award, recipient, desc,
- url, hours),
- title='give an award').render()
+ res = pages.AdminPage(content = pages.AdminAwardGive(award, recipient,
+ desc, url, hours),
+ title='give an award').render()
return res
- @validate(VAdmin(),
- award = VAwardByCodename('awardcn'))
+ @validate(validator.VAdmin(),
+ award=validator.VAwardByCodename('awardcn'))
def GET_winners(self, award):
if award is None:
abort(404, 'page not found')
- res = AdminPage(content = AdminAwardWinners(award),
- title='award winners').render()
+ res = pages.AdminPage(content = pages.AdminAwardWinners(award),
+ title='award winners').render()
return res
View
76 r2/r2/controllers/buttons.py
@@ -24,27 +24,20 @@
from pylons.controllers.util import abort
from pylons.i18n import _
-from r2.lib.pages import (Bookmarklets,
- BoringPage,
- ButtonDemoPanel,
- ButtonLite,
- WidgetDemoPanel,
- )
-from r2.lib.pages.things import wrap_links, NotFound
+import r2.models as models
+from r2.lib import pages
+from r2.lib.db.thing import NotFound
from r2.lib.utils import tup
-from r2.models import (DomainSR,
- FakeSubreddit,
- Link,
- )
+from r2.lib.wrapper import wrap_links
-from r2.controllers.validator import (VBoolean,
- VInt,
- VSanitizedUrl,
- nop,
- validate,
- )
+import r2.controllers.validator as validator
+from r2.controllers.validator import validate
-from reddit_base import RedditController
+from r2.controllers.reddit_base import RedditController
+
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
class ButtonsController(RedditController):
def get_wrapped_link(self, url, link = None, wrapper = None):
@@ -53,9 +46,11 @@ def get_wrapped_link(self, url, link = None, wrapper = None):
if link:
links = [link]
else:
- sr = None if isinstance(c.site, FakeSubreddit) else c.site
+ sr = c.site
+ if isinstance(c.site, models.FakeSubreddit):
+ sr = None
try:
- links = tup(Link._by_url(url, sr))
+ links = tup(models.Link._by_url(url, sr))
except NotFound:
pass
@@ -82,7 +77,7 @@ def get_wrapped_link(self, url, link = None, wrapper = None):
if wrapper:
return wrapper(None)
- @validate(buttontype = VInt('t', 1, 5))
+ @validate(buttontype=validator.VInt('t', 1, 5))
def GET_button_embed(self, buttontype):
if not buttontype:
abort(404)
@@ -90,11 +85,11 @@ def GET_button_embed(self, buttontype):
return self.redirect('/static/button/button%s.js' % buttontype,
code=301)
- @validate(buttonimage = VInt('i', 0, 14),
- title = nop('title'),
- url = VSanitizedUrl('url'),
- newwindow = VBoolean('newwindow', default = False),
- styled = VBoolean('styled', default=True))
+ @validate(buttonimage=validator.VInt('i', 0, 14),
+ title=validator.nop('title'),
+ url=validator.VSanitizedUrl('url'),
+ newwindow=validator.VBoolean('newwindow', default=False),
+ styled=validator.VBoolean('styled', default=True))
def GET_button_lite(self, buttonimage, title, url, styled, newwindow):
c.render_style = 'js'
c.response_content_type = 'text/javascript; charset=UTF-8'
@@ -109,29 +104,30 @@ def builder_wrapper(thing = None):
if not thing:
kw['url'] = url
kw['title'] = title
- return ButtonLite(thing,
- image = 1 if buttonimage is None else buttonimage,
- target = "_new" if newwindow else "_parent",
- styled = styled, **kw)
+
+ image = 1 if buttonimage is None else buttonimage
+ target = "_new" if newwindow else "_parent",
+ return pages.ButtonLite(thing, image=image, target=target,
+ styled=styled, **kw)
bjs = self.get_wrapped_link(url, wrapper = builder_wrapper)
return self.sendjs(bjs.render(), callback='', escape=False)
def GET_button_demo_page(self):
# no buttons for domain listings -> redirect to top level
- if isinstance(c.site, DomainSR):
+ if isinstance(c.site, models.DomainSR):
return self.redirect('/buttons')
- return BoringPage(_("reddit buttons"),
- show_sidebar = False,
- content=ButtonDemoPanel()).render()
+ return pages.BoringPage(_("reddit buttons"),
+ show_sidebar=False,
+ content=pages.ButtonDemoPanel()).render()
def GET_widget_demo_page(self):
- return BoringPage(_("reddit widget"),
- show_sidebar = False,
- content=WidgetDemoPanel()).render()
+ return pages.BoringPage(_("reddit widget"),
+ show_sidebar=False,
+ content=pages.WidgetDemoPanel()).render()
def GET_bookmarklets(self):
- return BoringPage(_("bookmarklets"),
- show_sidebar = False,
- content=Bookmarklets()).render()
+ return pages.BoringPage(_("bookmarklets"),
+ show_sidebar=False,
+ content=pages.Bookmarklets()).render()
View
5 r2/r2/controllers/captcha.py
@@ -26,6 +26,11 @@
from r2.controllers.reddit_base import RedditController
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
+
class CaptchaController(RedditController):
def GET_captchaimg(self, iden):
image = captcha.get_image(iden)
View
5 r2/r2/controllers/embed.py
@@ -34,6 +34,11 @@
from r2.controllers.reddit_base import RedditController
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
+
@memoize("renderurl_cached", time=60)
def renderurl_cached(path):
# Needed so http://reddit.com/help/ works
View
5 r2/r2/controllers/error.py
@@ -47,6 +47,11 @@
import os
os._exit(1)
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
+
NUM_FAILIENS = 3
redditbroke = \
View
20 r2/r2/controllers/errorlog.py
@@ -20,16 +20,22 @@
# Inc. All Rights Reserved.
###############################################################################
-from r2.lib.pages import AdminPage, AdminErrorLog
+from r2.lib import pages
+import r2.controllers.validator as validator
from r2.controllers.reddit_base import RedditController
-from r2.controllers.validator import VAdmin, validate
+from r2.controllers.validator import validate
+
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
class ErrorlogController(RedditController):
- @validate(VAdmin())
+ @validate(validator.VAdmin())
def GET_index(self):
- res = AdminPage(content = AdminErrorLog(),
- title = 'error log',
- show_sidebar = False
- ).render()
+ res = pages.AdminPage(content=pages.AdminErrorLog(),
+ title='error log',
+ show_sidebar=False
+ ).render()
return res
View
5 r2/r2/controllers/errors.py
@@ -26,6 +26,11 @@
from r2.lib.utils import Storage, tup
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
+
error_list = dict((
('USER_REQUIRED', _("please login to do that")),
('HTTPS_REQUIRED', _("this page must be accessed using https")),
View
19 r2/r2/controllers/feedback.py
@@ -20,18 +20,23 @@
# Inc. All Rights Reserved.
###############################################################################
-from r2.lib.pages import FormPage, SelfServeBlurb, FeedbackBlurb
+from r2.lib import pages
from r2.controllers.reddit_base import RedditController
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
+
+
class FeedbackController(RedditController):
def GET_ad_inq(self):
- return FormPage('advertise',
- content = SelfServeBlurb(),
- loginbox = False).render()
+ return pages.FormPage('advertise',
+ content=pages.SelfServeBlurb(),
+ loginbox=False).render()
def GET_feedback(self):
- return FormPage('feedback',
- content = FeedbackBlurb(),
- loginbox = False).render()
+ return pages.FormPage('feedback',
+ content=pages.FeedbackBlurb(),
+ loginbox=False).render()
View
819 r2/r2/controllers/front.py
@@ -33,78 +33,25 @@
from pylons.controllers.util import abort
from pylons.i18n import _
+import r2.config as config
import r2.lib.db.thing as thing
-from r2 import config
+import r2.models as models
from r2.config.extensions import is_api
-from r2.lib import sup
+from r2.lib import sup, pages, menus
from r2.lib.db.thing import NotFound
from r2.lib.emailer import has_opted_out, Email
from r2.lib.filters import _force_unicode
-from r2.lib.menus import (CommentSortMenu,
- NavButton,
- NavMenu,
- SearchSortMenu,
- )
-from r2.lib.pages import (AccountActivityPage,
- AdminModeInterstitial,
- BannedList,
- BoringPage,
- Captcha,
- Cnameframe,
- CommentVisitsBox,
- CommentPane,
- ContributorList,
- CreateSubreddit,
- DetailsPage,
- EditReddit,
- EnemyList,
- FlairPane,
- FormPage,
- FrameBuster,
- FriendList,
- Gold,
- GoldPayment,
- InfoBar,
- LinkCommentSep,
- LinkInfoPage,
- LoginPage,
- ModList,
- NewLink,
- OptOut,
- PaneStack,
- Password,
- PermalinkMessage,
- PrefApps,
- PrefDelete,
- PrefFeeds,
- PrefUpdate,
- PrefOptions,
- PrefOTP,
- PrefsPage,
- Reddit,
- RedditAds,
- RegisterPage,
- ResetPassword,
- RulesPage,
- SearchPage,
- SelfServiceOatmeal,
- SubredditsPage,
- SubredditStylesheet,
- Thanks,
- TryCompact,
- UserAwards,
- UserText,
- trafficpages,
- )
-from r2.lib.pages.things import wrap_links, default_thing_wrapper
-from r2.lib.search import (SearchQuery,
- SubredditSearchQuery,
- SearchException,
+from r2.lib.search import (#Classes
InvalidQuery,
+ SearchException,
+ SearchQuery,
+ SubredditSearchQuery,
)
from r2.lib.strings import strings
from r2.lib.template_helpers import get_domain, add_sr
-from r2.lib.utils import (UrlParser,
+from r2.lib.utils import (#Classes
+ UrlParser,
+ #Functions
check_cheating,
link_duplicates,
link_from_url,
@@ -116,72 +63,32 @@
)
from r2.lib.utils.trial_utils import trial_info
from r2.lib.wrapped import Wrapped
-from r2.models import (Account,
- AllSR,
- Award,
- ContribSR,
- DefaultSR,
- IDBuilder,
- EmailVerificationToken,
- FakeSubreddit,
- Jury,
- Link,
- LinkListing,
- LinkOnTrial,
- ModAction,
- ModActionListing,
- ModContribSR,
- ModSR,
- MultiReddit,
- OAuth2Client,
- PasswordResetToken,
- QueryBuilder,
- SearchBuilder,
- Subreddit,
- MAX_RECURSION,
- Friends,
- )
+from r2.lib.wrapper import wrap_links, default_thing_wrapper
+import r2.controllers.validator as validator
from r2.controllers.api_docs import api_doc, api_section
from r2.controllers.errors import errors, UserRequiredException
from r2.controllers.listingcontroller import ListingController
-from r2.controllers.reddit_base import (RedditController,
+from r2.controllers.reddit_base import (#Classes
+ RedditController,
+ #Functions
base_listing,
paginated_listing,
prevent_framing_and_css
)
-from r2.controllers.validator import (VAdmin,
- VBoolean,
- VByName,
- VCount,
- VCommentByID,
- VCommentID,
- VDestination,
- VInt,
- VLength,
- VLink,
- VMenu,
- VModhash,
- VOneOf,
- VOneTimeToken,
- VPrintable,
- VRequired,
- VSponsorAdmin,
- VTrafficViewer,
- VUser,
- can_view_link_comments,
- can_comment_link,
- nop,
- validate,
- )
+from r2.controllers.validator import validate
+
+__all__ = [
+ #Constants Only, use @export for functions/classes
+ ]
class FrontController(RedditController):
allow_stylesheets = True
- @validate(article = VLink('article'),
- comment = VCommentID('comment'))
+ @validate(article=validator.VLink('article'),
+ comment=validator.VCommentID('comment'))
def GET_oldinfo(self, article, type, dest, rest=None, comment=''):
"""Legacy: supporting permalink pages from '06,
and non-search-engine-friendly links"""
@@ -221,9 +128,9 @@ def GET_random(self):
random.shuffle(links)
- builder = IDBuilder(links, skip = True,
- keep_fn = lambda x: x.fresh,
- num = 1)
+ builder = models.IDBuilder(links, skip=True,
+ keep_fn=lambda x: x.fresh,
+ num=1)
links = builder.get_items()[0]
if links:
@@ -233,19 +140,19 @@ def GET_random(self):
return self.redirect(add_sr('/'))
@prevent_framing_and_css()
- @validate(VAdmin(),
- thing = VByName('article'),
- oldid36 = nop('article'),
- after=nop('after'),
- before=nop('before'),
- count=VCount('count'))
+ @validate(validator.VAdmin(),
+ thing=validator.VByName('article'),
+ oldid36=validator.nop('article'),
+ after=validator.nop('after'),
+ before=validator.nop('before'),
+ count=validator.VCount('count'))
def GET_details(self, thing, oldid36, after, before, count):
"""The (now deprecated) details page. Content on this page
has been subsubmed by the presence of the LinkInfoBar on the
rightbox, so it is only useful for Admin-only wizardry."""
if not thing:
try:
- link = Link._byID36(oldid36)
+ link = models.Link._byID36(oldid36)
return self.redirect('/details/' + link._fullname)
except (NotFound, ValueError):
abort(404)
@@ -257,15 +164,16 @@ def GET_details(self, thing, oldid36, after, before, count):
else:
kw['after'] = after
kw['reverse'] = False
- return DetailsPage(thing=thing, expand_children=False, **kw).render()
+ return pages.DetailsPage(thing=thing, expand_children=False, **kw
+ ).render()
def GET_selfserviceoatmeal(self):
- return BoringPage(_("self service help"),
- show_sidebar = False,
- content = SelfServiceOatmeal()).render()
+ return pages.BoringPage(_("self service help"),
+ show_sidebar=False,
+ content=pages.SelfServiceOatmeal()).render()
- @validate(article = VLink('article'))
+ @validate(article=validator.VLink('article'))
def GET_shirt(self, article):
if not can_view_link_comments(article):
abort(403, 'forbidden')
@@ -302,23 +210,23 @@ def _comment_visits(self, article, user, new_visit=None):
return old_visits
- @validate(article = VLink('article'),
- comment = VCommentID('comment'),
- context = VInt('context', min = 0, max = 8),
- sort = VMenu('controller', CommentSortMenu),
- limit = VInt('limit'),
- depth = VInt('depth'))
+ @validate(article=validator.VLink('article'),
+ comment=validator.VCommentID('comment'),
+ context=validator.VInt('context', min = 0, max = 8),
+ sort=validator.VMenu('controller', menus.CommentSortMenu),
+ limit=validator.VInt('limit'),
+ depth=validator.VInt('depth'))
def POST_comments(self, article, comment, context, sort, limit, depth):
# VMenu validator will save the value of sort before we reach this
# point. Now just redirect to GET mode.
return self.redirect(request.fullpath + query_string(dict(sort=sort)))
- @validate(article = VLink('article'),
- comment = VCommentID('comment'),
- context = VInt('context', min = 0, max = 8),
- sort = VMenu('controller', CommentSortMenu),
- limit = VInt('limit'),
- depth = VInt('depth'))
+ @validate(article=validator.VLink('article'),
+ comment=validator.VCommentID('comment'),
+ context=validator.VInt('context', min = 0, max = 8),
+ sort=validator.VMenu('controller', menus.CommentSortMenu),
+ limit=validator.VInt('limit'),
+ depth=validator.VInt('depth'))
@api_doc(api_section.listings,
uri='/comments/{article}',
extensions=['json', 'xml'])
@@ -327,7 +235,7 @@ def GET_comments(self, article, comment, context, sort, limit, depth):
if comment and comment.link_id != article._id:
return self.abort404()
- sr = Subreddit._byID(article.sr_id, True)
+ sr = models.Subreddit._byID(article.sr_id, True)
if sr.name == g.takedown_sr:
request.environ['REDDIT_TAKEDOWN'] = article._fullname
@@ -377,12 +285,12 @@ def GET_comments(self, article, comment, context, sort, limit, depth):
kw = {}
# allow depth to be reset (I suspect I'll turn the VInt into a
# validator on my next pass of .compact)
- if depth is not None and 0 < depth < MAX_RECURSION:
+ if depth is not None and 0 < depth < models.MAX_RECURSION:
kw['max_depth'] = depth
elif c.render_style == "compact":
kw['max_depth'] = 5
- displayPane = PaneStack()
+ displayPane = pages.PaneStack()
# allow the user's total count preferences to be overwritten
# (think of .embed as the use case together with depth=1)
@@ -392,24 +300,25 @@ def GET_comments(self, article, comment, context, sort, limit, depth):
if c.user_is_loggedin and c.user.gold:
if num > g.max_comments_gold:
- displayPane.append(InfoBar(message =
- strings.over_comment_limit_gold
- % max(0, g.max_comments_gold)))
+ message = (strings.over_comment_limit_gold %
+ max(0, g.max_comments_gold))
+ displayPane.append(pages.InfoBar(message=message))
num = g.max_comments_gold
elif num > g.max_comments:
if limit:
- displayPane.append(InfoBar(message =
- strings.over_comment_limit
- % dict(max=max(0, g.max_comments),
- goldmax=max(0,
- g.max_comments_gold))))
+ message = (strings.over_comment_limit %
+ dict(max=max(0, g.max_comments),
+ goldmax=max(0, g.max_comments_gold))
+ )
+ displayPane.append(pages.InfoBar(message=message))
num = g.max_comments
# if permalink page, add that message first to the content
if comment:
- displayPane.append(PermalinkMessage(article.make_permalink_slow()))
+ permalink = pages.PermalinkMessage(article.make_permalink_slow())
+ displayPane.append(permalink)
- displayPane.append(LinkCommentSep())
+ displayPane.append(pages.LinkCommentSep())
# insert reply box only for logged in user
if c.user_is_loggedin and can_comment_link(article) and not is_api():
@@ -419,13 +328,14 @@ def GET_comments(self, article, comment, context, sort, limit, depth):
age = c.start_time - article._date
if age.days < g.REPLY_AGE_LIMIT:
display = True
- displayPane.append(UserText(item = article, creating = True,
- post_form = 'comment',
- display = display,
- cloneable = True))
+ displayPane.append(pages.UserText(item=article,
+ creating=True,
+ post_form='comment',
+ display=display,
+ cloneable=True))
if previous_visits:
- displayPane.append(CommentVisitsBox(previous_visits))
+ displayPane.append(pages.CommentVisitsBox(previous_visits))
# Used in later "more comments" renderings
pv_hex = md5(repr(previous_visits)).hexdigest()
g.cache.set(pv_hex, previous_visits, time=g.comment_visits_period)
@@ -435,8 +345,9 @@ def GET_comments(self, article, comment, context, sort, limit, depth):
c.previous_visits = previous_visits
# finally add the comment listing
- displayPane.append(CommentPane(article, CommentSortMenu.operator(sort),
- comment, context, num, **kw))
+ displayPane.append(pages.CommentPane(article,
+ menus.CommentSortMenu.operator(sort),
+ comment, context, num, **kw))
subtitle_buttons = []
@@ -458,13 +369,14 @@ def GET_comments(self, article, comment, context, sort, limit, depth):
self._add_show_comments_link(subtitle_buttons, article, num,
g.max_comments_gold, gold=True)
- res = LinkInfoPage(link = article, comment = comment,
- content = displayPane,
- page_classes = ['comments-page'],
- subtitle = subtitle,
- subtitle_buttons = subtitle_buttons,
- nav_menus = [CommentSortMenu(default = sort)],
- infotext = infotext).render()
+ res = pages.LinkInfoPage(link=article,
+ comment=comment,
+ content=displayPane,
+ page_classes=['comments-page'],
+ subtitle=subtitle,
+ subtitle_buttons=subtitle_buttons,
+ nav_menus=[menus.CommentSortMenu(default=sort)],
+ infotext=infotext).render()
return res
def _add_show_comments_link(self, array, article, num, max_comm, gold=False):
@@ -485,21 +397,21 @@ def _add_show_comments_link(self, array, article, num, max_comm, gold=False):
more_link = article.make_permalink_slow() + limit_param
array.append( (link_text, more_link, link_class) )
- @validate(VUser(),
- name = nop('name'))
+ @validate(validator.VUser(),
+ name=validator.nop('name'))
def GET_newreddit(self, name):
"""Create a community form"""
title = _('create a reddit')
- content=CreateSubreddit(name = name or '')
- res = FormPage(_("create a community"),
- content = content,
- ).render()
+ content=pages.CreateSubreddit(name = name or '')
+ res = pages.FormPage(_("create a community"),
+ content=content,
+ ).render()
return res
def GET_stylesheet(self):
# de-stale the subreddit object so we don't poison nginx's cache
- if not isinstance(c.site, FakeSubreddit):
- c.site = Subreddit._byID(c.site._id, data=True, stale=False)
+ if not isinstance(c.site, models.FakeSubreddit):
+ c.site = models.Subreddit._byID(c.site._id, data=True, stale=False)
if hasattr(c.site,'stylesheet_contents') and not g.css_killswitch:
c.allow_loggedin_cache = True
@@ -517,26 +429,26 @@ def GET_stylesheet(self):
def _make_moderationlog(self, srs, num, after, reverse, count, mod=None, action=None):
if mod and action:
- query = Subreddit.get_modactions(srs, mod=mod, action=None)
+ query = models.Subreddit.get_modactions(srs, mod=mod, action=None)
def keep_fn(ma):
return ma.action == action
else:
- query = Subreddit.get_modactions(srs, mod=mod, action=action)
+ query = models.Subreddit.get_modactions(srs, mod=mod, action=action)
def keep_fn(ma):
return True
- builder = QueryBuilder(query, skip=True, num=num, after=after,
- keep_fn=keep_fn, count=count,
- reverse=reverse,
- wrap=default_thing_wrapper())
- listing = ModActionListing(builder)
+ builder = models.QueryBuilder(query, skip=True, num=num, after=after,
+ keep_fn=keep_fn, count=count,
+ reverse=reverse,
+ wrap=default_thing_wrapper())
+ listing = models.ModActionListing(builder)
pane = listing.listing()
return pane
@prevent_framing_and_css(allow_cname_frame=True)
@paginated_listing(max_page_size=500, backend='cassandra')
- @validate(mod=nop('mod'),
- action=VOneOf('type', ModAction.actions))
+ @validate(mod=validator.nop('mod'),
+ action=validator.VOneOf('type', models.ModAction.actions))
@api_doc(api_section.moderation)
def GET_moderationlog(self, num, after, reverse, count, mod, action):
if not c.user_is_loggedin or not (c.user_is_admin or
@@ -545,48 +457,52 @@ def GET_moderationlog(self, num, after, reverse, count, mod, action):
if mod:
try:
- mod = Account._by_name(mod, allow_deleted=True)
+ mod = models.Account._by_name(mod, allow_deleted=True)
except NotFound:
mod = None
- if isinstance(c.site, (MultiReddit, ModSR)):
- srs = Subreddit._byID(c.site.sr_ids, return_dict=False)
+ if isinstance(c.site, (models.MultiReddit, models.ModSR)):
+ srs = models.Subreddit._byID(c.site.sr_ids, return_dict=False)
# grab all moderators
- mod_ids = set(Subreddit.get_all_mod_ids(srs))
- mods = Account._byID(mod_ids, data=True)
+ mod_ids = set(models.Subreddit.get_all_mod_ids(srs))
+ mods = models.Account._byID(mod_ids, data=True)
pane = self._make_moderationlog(srs, num, after, reverse, count,
mod=mod, action=action)
- elif isinstance(c.site, FakeSubreddit):
+ elif isinstance(c.site, models.FakeSubreddit):
return self.abort404()
else:
mod_ids = c.site.moderators
- mods = Account._byID(mod_ids, data=True)
+ mods = models.Account._byID(mod_ids, data=True)
pane = self._make_moderationlog(c.site, num, after, reverse, count,
mod=mod, action=action)
- panes = PaneStack()
+ panes = pages.PaneStack()
panes.append(pane)
- action_buttons = [NavButton(_('all'), None, opt='type', css_class='primary')]
- for a in ModAction.actions:
- action_buttons.append(NavButton(ModAction._menu[a], a, opt='type'))
+ action_buttons = [menus.NavButton(_('all'), None, opt='type',
+ css_class='primary')]
+ for a in models.ModAction.actions:
+ action_buttons.append(menus.NavButton(models.ModAction._menu[a], a,
+ opt='type'))
- mod_buttons = [NavButton(_('all'), None, opt='mod', css_class='primary')]
+ mod_buttons = [menus.NavButton(_('all'), None, opt='mod',
+ css_class='primary')]
for mod_id in mod_ids:
mod = mods[mod_id]
- mod_buttons.append(NavButton(mod.name, mod.name, opt='mod'))
+ mod_buttons.append(menus.NavButton(mod.name, mod.name, opt='mod'))
base_path = request.path
- menus = [NavMenu(action_buttons, base_path=base_path,
- title=_('filter by action'), type='lightdrop', css_class='modaction-drop'),
- NavMenu(mod_buttons, base_path=base_path,
- title=_('filter by moderator'), type='lightdrop')]
- return EditReddit(content=panes,
- nav_menus=menus,
- location="log",
- extension_handling=False).render()
+ menus = [menus.NavMenu(action_buttons, base_path=base_path,
+ title=_('filter by action'), type='lightdrop',
+ css_class='modaction-drop'),
+ menus.NavMenu(mod_buttons, base_path=base_path,
+ title=_('filter by moderator'), type='lightdrop')]
+ return pages.EditReddit(content=panes,
+ nav_menus=menus,
+ location="log",
+ extension_handling=False).render()
def _make_spamlisting(self, location, num, after, reverse, count):
if location == 'reports':
@@ -604,11 +520,11 @@ def _make_spamlisting(self, location, num, after, reverse, count):
raise ValueError
if isinstance(query, thing.Query):
- builder_cls = QueryBuilder
+ builder_cls = models.QueryBuilder
elif isinstance (query, list):
- builder_cls = QueryBuilder
+ builder_cls = models.QueryBuilder
else:
- builder_cls = IDBuilder
+ builder_cls = models.IDBuilder
def keep_fn(x):
# no need to bother mods with banned users, or deleted content
@@ -636,12 +552,12 @@ def keep_fn(x):
raise ValueError
builder = builder_cls(query,
- skip = True,
- num = num, after = after,
- keep_fn = keep_fn,
- count = count, reverse = reverse,
- wrap = ListingController.builder_wrapper)
- listing = LinkListing(builder)
+ skip=True,
+ num=num, after = after,
+ keep_fn=keep_fn,
+ count=count, reverse = reverse,
+ wrap=ListingController.builder_wrapper)
+ listing = models.LinkListing(builder)
pane = listing.listing()
# Indicate that the comment tree wasn't built for comments
@@ -656,11 +572,11 @@ def _edit_modcontrib_reddit(self, location, num, after, reverse, count, created)
if not c.user_is_loggedin:
return self.abort404()
- if isinstance(c.site, (ModSR, MultiReddit)):
+ if isinstance(c.site, (models.ModSR, models.MultiReddit)):
level = 'mod'
- elif isinstance(c.site, ContribSR):
+ elif isinstance(c.site, models.ContribSR):
level = 'contrib'
- elif isinstance(c.site, AllSR):
+ elif isinstance(c.site, models.AllSR):
level = 'all'
else:
raise ValueError
@@ -676,9 +592,9 @@ def _edit_modcontrib_reddit(self, location, num, after, reverse, count, created)
else:
return self.abort404()
- return EditReddit(content=pane,
- location=location,
- extension_handling=extension_handling).render()
+ return pages.EditReddit(content=pane,
+ location=location,
+ extension_handling=extension_handling).render()
def _edit_normal_reddit(self, location, num, after, reverse, count, created,
name, user):
@@ -686,23 +602,23 @@ def _edit_normal_reddit(self, location, num, after, reverse, count, created,
is_moderator = c.user_is_loggedin and c.site.is_moderator(c.user) or c.user_is_admin
extension_handling = False
if is_moderator and location == 'edit':
- pane = PaneStack()
+ pane = pages.PaneStack()
if created == 'true':
- pane.append(InfoBar(message = strings.sr_created))
+ pane.append(pages.InfoBar(message=strings.sr_created))
c.allow_styles = True
- c.site = Subreddit._byID(c.site._id, data=True, stale=False)
- pane.append(CreateSubreddit(site = c.site))
+ c.site = models.Subreddit._byID(c.site._id, data=True, stale=False)
+ pane.append(pages.CreateSubreddit(site = c.site))
elif location == 'moderators':
- pane = ModList(editable = is_moderator)
+ pane = pages.ModList(editable=is_moderator)
elif is_moderator and location == 'banned':
- pane = BannedList(editable = is_moderator)
+ pane = pages.BannedList(editable=is_moderator)
elif (location == 'contributors' and
# On public reddits, only moderators can see the whitelist.
# On private reddits, all contributors can see each other.
(c.site.type != 'public' or
(c.user_is_loggedin and
(c.site.is_moderator(c.user) or c.user_is_admin)))):
- pane = ContributorList(editable = is_moderator)
+ pane = pages.ContributorList(editable = is_moderator)
elif (location == 'stylesheet'
and c.site.can_change_stylesheet(c.user)
and not g.css_killswitch):
@@ -713,8 +629,9 @@ def _edit_normal_reddit(self, location, num, after, reverse, count, created,
else:
stylesheet_contents = ''
c.allow_styles = True
- pane = SubredditStylesheet(site = c.site,
- stylesheet_contents = stylesheet_contents)
+ pane = pages.SubredditStylesheet(site=c.site,
+ stylesheet_contents=
+ stylesheet_contents)
elif (location in ('reports', 'spam', 'trials', 'modqueue', 'unmoderated')
and is_moderator):
c.allow_styles = True
@@ -722,49 +639,49 @@ def _edit_normal_reddit(self, location, num, after, reverse, count, created,
if c.user.pref_private_feeds:
extension_handling = "private"
elif (is_moderator or c.user_is_sponsor) and location == 'traffic':
- pane = trafficpages.SubredditTraffic()
+ pane = pages.trafficpages.SubredditTraffic()
elif is_moderator and location == 'flair':
c.allow_styles = True
- pane = FlairPane(num, after, reverse, name, user)
+ pane = pages.FlairPane(num, after, reverse, name, user)
elif c.user_is_sponsor and location == 'ads':
- pane = RedditAds()
+ pane = pages.RedditAds()
elif (location == "about") and is_api():
return self.redirect(add_sr('about.json'), code=301)
else:
return self.abort404()
- return EditReddit(content=pane,
- location=location,
- extension_handling=extension_handling).render()
+ return pages.EditReddit(content=pane,
+ location=location,
+ extension_handling=extension_handling).render()
@base_listing
@prevent_framing_and_css(allow_cname_frame=True)
- @validate(location = nop('location'),
- created = VOneOf('created', ('true','false'),
- default = 'false'),
- name = nop('name'))
+ @validate(location=validator.nop('location'),
+ created=validator.VOneOf('created', ('true','false'),
+ default='false'),
+ name=validator.nop('name'))
def GET_editreddit(self, location, num, after, reverse, count, created,
name):
"""Edit reddit form."""
user = None
if name:
try:
- user = Account._by_name(name)
+ user = models.Account._by_name(name)
except NotFound:
c.errors.add(errors.USER_DOESNT_EXIST, field='name')
c.profilepage = True
- if isinstance(c.site, ModContribSR):
+ if isinstance(c.site, models.ModContribSR):
return self._edit_modcontrib_reddit(location, num, after, reverse,
count, created)
- elif isinstance(c.site, MultiReddit):
+ elif isinstance(c.site, models.MultiReddit):
if not (c.user_is_admin or c.site.is_moderator(c.user)):
self.abort403()
return self._edit_modcontrib_reddit(location, num, after, reverse,
count, created)
- elif isinstance(c.site, AllSR) and c.user_is_admin:
+ elif isinstance(c.site, models.AllSR) and c.user_is_admin:
return self._edit_modcontrib_reddit(location, num, after, reverse,
count, created)
- elif isinstance(c.site, FakeSubreddit):
+ elif isinstance(c.site, models.FakeSubreddit):
return self.abort404()
else:
return self._edit_normal_reddit(location, num, after, reverse,
@@ -775,20 +692,21 @@ def GET_about(self):
"""Return information about the subreddit.
Data includes the subscriber count, description, and header image."""
- if not is_api() or isinstance(c.site, FakeSubreddit):
+ if not is_api() or isinstance(c.site, models.FakeSubreddit):
return self.abort404()
- return Reddit(content = Wrapped(c.site)).render()
+ return pages.Reddit(content=Wrapped(c.site)).render()
def GET_awards(self):
"""The awards page."""
- return BoringPage(_("awards"), content = UserAwards()).render()
+ return pages.BoringPage(_("awards"), content=pages.UserAwards()
+ ).render()
# filter for removing punctuation which could be interpreted as search syntax
related_replace_regex = re.compile(r'[?\\&|!{}+~^()"\':*-]+')
related_replace_with = ' '
@base_listing
- @validate(article = VLink('article'))
+ @validate(article=validator.VLink('article'))
def GET_related(self, num, article, after, reverse, count):
"""Related page: performs a search using title of article as
the search query.
@@ -813,32 +731,32 @@ def GET_related(self, num, article, after, reverse, count):
pane = self._search(q, num=num, after=after, reverse=reverse,
count=count)[2]
- return LinkInfoPage(link=article, content=pane,
- subtitle=_('related')).render()
+ return pages.LinkInfoPage(link=article, content=pane,
+ subtitle=_('related')).render()
@base_listing
- @validate(article = VLink('article'))
+ @validate(article=validator.VLink('article'))
def GET_duplicates(self, article, num, after, reverse, count):
if not can_view_link_comments(article):
abort(403, 'forbidden')
links = link_duplicates(article)
links.sort(key=attrgetter('num_comments'), reverse=True)
- builder = IDBuilder([ link._fullname for link in links ],
- num = num, after = after, reverse = reverse,
- count = count, skip = False)
- listing = LinkListing(builder).listing()
-
- res = LinkInfoPage(link = article,
- comment = None,
- duplicates = links,
- content = listing,
- subtitle = _('other discussions')).render()
+ builder = models.IDBuilder([ link._fullname for link in links ],
+ num=num, after=after, reverse=reverse,
+ count=count, skip=False)
+ listing = models.LinkListing(builder).listing()
+
+ res = pages.LinkInfoPage(link=article,
+ comment=None,
+ duplicates=links,
+ content=listing,
+ subtitle=_('other discussions')).render()
return res
@base_listing
- @validate(query = nop('q'))
+ @validate(query=validator.nop('q'))
@api_doc(api_section.subreddits, uri='/reddits/search', extensions=['json', 'xml'])
def GET_search_reddits(self, query, reverse, after, count, num):
"""Search reddits by title and description."""
@@ -848,23 +766,26 @@ def GET_search_reddits(self, query, reverse, after, count, num):
after=after, count=count,
skip_deleted_authors=False)
- res = SubredditsPage(content=spane,
- prev_search=query,
- elapsed_time=etime,
- num_results=results.hits,
- # update if we ever add sorts
- search_params={},
- title=_("search results"),
- simple=True).render()
+ res = pages.SubredditsPage(content=spane,
+ prev_search=query,
+ elapsed_time=etime,
+ num_results=results.hits,
+ # update if we ever add sorts
+ search_params={},
+ title=_("search results"),
+ simple=True
+ ).render()
return res
search_help_page = "/help/search"
verify_langs_regex = re.compile(r"\A[a-z][a-z](,[a-z][a-z])*\Z")
@base_listing
- @validate(query=VLength('q', max_length=512),
- sort=VMenu('sort', SearchSortMenu, remember=False),
- restrict_sr=VBoolean('restrict_sr', default=False),
- syntax=VOneOf('syntax', options=SearchQuery.known_syntaxes))
+ @validate(query=validator.VLength('q', max_length=512),
+ sort=validator.VMenu('sort', menus.SearchSortMenu,
+ remember=False),
+ restrict_sr=validator.VBoolean('restrict_sr', default=False),
+ syntax=validator.VOneOf('syntax',
+ options=SearchQuery.known_syntaxes))
@api_doc(api_section.search, extensions=['json', 'xml'])
def GET_search(self, query, num, reverse, after, count, sort, restrict_sr,
syntax):
@@ -875,7 +796,7 @@ def GET_search(self, query, num, reverse, after, count, sort, restrict_sr,
return self.redirect("/submit" + query_string({'url':url}))
if not restrict_sr:
- site = DefaultSR()
+ site = models.DefaultSR()
else:
site = c.site
@@ -913,18 +834,20 @@ def GET_search(self, query, num, reverse, after, count, sort, restrict_sr,
else:
cleanup_message = strings.completely_invalid_search_query
- res = SearchPage(_('search results'), query, etime, results.hits,
- content=spane,
- nav_menus=[SearchSortMenu(default=sort)],
- search_params=dict(sort=sort),
- infotext=cleanup_message,
- simple=False, site=c.site,
- restrict_sr=restrict_sr,
- syntax=syntax,
- converted_data=q.converted_data,
- facets=results.subreddit_facets,
- sort=sort,
- ).render()
+ res = pages.SearchPage(_('search results'), query, etime,
+ results.hits,
+ content=spane,
+ nav_menus=
+ [menus.SearchSortMenu(default=sort)],
+ search_params=dict(sort=sort),
+ infotext=cleanup_message,
+ simple=False, site=c.site,
+ restrict_sr=restrict_sr,
+ syntax=syntax,
+ converted_data=q.converted_data,
+ facets=results.subreddit_facets,
+ sort=sort,
+ ).render()
return res
except SearchException + (socket.error,) as e:
@@ -935,13 +858,14 @@ def _search(self, query_obj, num, after, reverse, count=0,
"""Helper function for interfacing with search. Basically a
thin wrapper for SearchBuilder."""
- builder = SearchBuilder(query_obj,
- after = after, num = num, reverse = reverse,
- count = count,
- wrap = ListingController.builder_wrapper,
- skip_deleted_authors=skip_deleted_authors)
+ builder = models.SearchBuilder(query_obj,
+ after=after, num=num, reverse=reverse,
+ count=count,
+ wrap=ListingController.builder_wrapper,
+ skip_deleted_authors=
+ skip_deleted_authors)
- listing = LinkListing(builder, show_nums=True)
+ listing = models.LinkListing(builder, show_nums=True)
# have to do it in two steps since total_num and timing are only
# computed after fetch_more
@@ -953,17 +877,18 @@ def _search(self, query_obj, num, after, reverse, count=0,
return builder.results, timing, res
- @validate(VAdmin(),
- comment = VCommentByID('comment_id'))
+ @validate(validator.VAdmin(),
+ comment=validator.VCommentByID('comment_id'))
def GET_comment_by_id(self, comment):
href = comment.make_permalink_slow(context=5, anchor=True)
return self.redirect(href)
- @validate(url = VRequired('url', None),
- title = VRequired('title', None),
- text = VRequired('text', None),
- selftext = VRequired('selftext', None),
- then = VOneOf('then', ('tb','comments'), default = 'comments'))
+ @validate(url=validator.VRequired('url', None),
+ title=validator.VRequired('title', None),
+ text=validator.VRequired('text', None),
+ selftext=validator.VRequired('selftext', None),
+ then=validator.VOneOf('then', ('tb','comments'),
+ default='comments'))
def GET_submit(self, url, title, text, selftext, then):
"""Submit form."""
resubmit = request.get.get('resubmit')
@@ -975,9 +900,9 @@ def GET_submit(self, url, title, text, selftext, then):
elif links:
infotext = (strings.multiple_submitted
% links[0].resubmit_link())
- res = BoringPage(_("seen it"),
- content = wrap_links(links),
- infotext = infotext).render()
+ res = pages.BoringPage(_("seen it"),
+ content=wrap_links(links),
+ infotext=infotext).render()
return res
if not c.user_is_loggedin:
@@ -986,29 +911,29 @@ def GET_submit(self, url, title, text, selftext, then):
if not (c.default_sr or c.site.can_submit(c.user)):
abort(403, "forbidden")
- captcha = Captcha() if c.user.needs_captcha() else None
- sr_names = (Subreddit.submit_sr_names(c.user) or
- Subreddit.submit_sr_names(None))
-
- return FormPage(_("submit"),
- show_sidebar = True,
- page_classes=['submit-page'],
- content=NewLink(url=url or '',
- title=title or '',
- text=text or '',
- selftext=selftext or '',
- subreddits = sr_names,
- captcha=captcha,
- resubmit=resubmit,
- then = then)).render()
+ captcha = pages.Captcha() if c.user.needs_captcha() else None
+ sr_names = (models.Subreddit.submit_sr_names(c.user) or
+ models.Subreddit.submit_sr_names(None))
+
+ return pages.FormPage(_("submit"),
+ show_sidebar=True,
+ page_classes=['submit-page'],
+ content=pages.NewLink(url=url or '',
+ title=title or '',
+ text=text or '',
+ selftext=selftext or '',
+ subreddits = sr_names,
+ captcha=captcha,
+ resubmit=resubmit,
+ then=then)).render()
def GET_frame(self):
"""used for cname support. makes a frame and
puts the proper url as the frame source"""
sub_domain = request.environ.get('sub_domain')
original_path = request.environ.get('original_path')
- sr = Subreddit._by_domain(sub_domain)
- return Cnameframe(original_path, sr, sub_domain).render()
+ sr = models.Subreddit._by_domain(sub_domain)
+ return pages.Cnameframe(original_path, sr, sub_domain).render()
def GET_framebuster(self, what = None, blah = None):
@@ -1029,25 +954,25 @@ def GET_framebuster(self, what = None, blah = None):
if not c.site.domain:
return ""
elif c.cname:
- return FrameBuster(login = (what == "login")).render()
+ return pages.FrameBuster(login=(what == "login")).render()
else:
path = "/framebuster/"
if c.user_is_loggedin:
path += "login/"
u = UrlParser(path + str(random.random()))
- u.mk_cname(require_frame = False, subreddit = c.site,
- port = request.port)
+ u.mk_cname(require_frame=False, subreddit=c.site,
+ port=request.port)
return self.redirect(u.unparse())
# the user is not logged in or there is no cname.
- return FrameBuster(login = False).render()
+ return pages.FrameBuster(login=False).render()
def GET_catchall(self):
return self.abort404()
- @validate(period = VInt('seconds',
- min = sup.MIN_PERIOD,
- max = sup.MAX_PERIOD,
- default = sup.MIN_PERIOD))
+ @validate(period=validator.VInt('seconds',
+ min=sup.MIN_PERIOD,
+ max=sup.MAX_PERIOD,
+ default=sup.MIN_PERIOD))
def GET_sup(self, period):
#dont cache this, it's memoized elsewhere
c.used_cache = True
@@ -1060,50 +985,52 @@ def GET_sup(self, period):
return self.abort404()
- @validate(VTrafficViewer('article'),
- article = VLink('article'))
+ @validate(validator.VTrafficViewer('article'),
+ article=validator.VLink('article'))
def GET_traffic(self, article):
- content = trafficpages.PromotedLinkTraffic(article)
+ content = pages.trafficpages.PromotedLinkTraffic(article)
if c.render_style == 'csv':
c.response.content = content.as_csv()
return c.response
- return LinkInfoPage(link=article,
- page_classes=["promoted-traffic"],
- comment=None,
- content=content).render()
+ return pages.LinkInfoPage(link=article,
+ page_classes=["promoted-traffic"],
+ comment=None,
+ content=content).render()
- @validate(VSponsorAdmin())
+ @validate(validator.VSponsorAdmin())
def GET_site_traffic(self):
- return trafficpages.SitewideTrafficPage().render()
+ return pages.trafficpages.SitewideTrafficPage().render()
- @validate(VSponsorAdmin())
+ @validate(validator.VSponsorAdmin())
def GET_lang_traffic(self, langcode):
- return trafficpages.LanguageTrafficPage(langcode).render()
+ return pages.trafficpages.LanguageTrafficPage(langcode).render()
- @validate(VSponsorAdmin())
+ @validate(validator.VSponsorAdmin())
def GET_advert_traffic(self, code):
- return trafficpages.AdvertTrafficPage(code).render()
+ return pages.trafficpages.AdvertTrafficPage(code).render()
- @validate(VUser())
+ @validate(validator.VUser())
def GET_account_activity(self):
- return AccountActivityPage().render()
+ return pages.AccountActivityPage().render()
def GET_rules(self):
- return BoringPage(_("rules of reddit"), show_sidebar=False,
- content=RulesPage(), page_classes=["rulespage-body"]
- ).render()
+ return pages.BoringPage(_("rules of reddit"), show_sidebar=False,
+ content=pages.RulesPage(),
+ page_classes=["rulespage-body"]
+ ).render()
class FormsController(RedditController):
def GET_password(self):
"""The 'what is my password' page"""
- return BoringPage(_("password"), content=Password()).render()
+ return pages.BoringPage(_("password"), content=pages.Password()
+ ).render()
- @validate(VUser(),
- dest = VDestination(),
- reason = nop('reason'))
+ @validate(validator.VUser(),
+ dest=validator.VDestination(),
+ reason=validator.nop('reason'))
def GET_verify(self, dest, reason):
if c.user.email_verified:
content = InfoBar(message = strings.email_verified)
@@ -1115,15 +1042,15 @@ def GET_verify(self, dest, reason):
else:
infomsg = strings.verify_email
- content = PaneStack(
- [InfoBar(message = infomsg),
- PrefUpdate(email = True, verify = True,
- password = False)])
- return BoringPage(_("verify email"), content = content).render()
+ panes = [pages.InfoBar(message=infomsg),
+ pages.PrefUpdate(email=True, verify=True, password=False)]
+ content = pages.PaneStack(panes)
+ return pages.BoringPage(_("verify email"), content = content).render()
- @validate(VUser(),
- token=VOneTimeToken(EmailVerificationToken, "key"),
- dest=VDestination(default="/prefs/update"))
+ @validate(validator.VUser(),
+ token=validator.VOneTimeToken(models.EmailVerificationToken,
+ "key"),
+ dest=validator.VDestination(default="/prefs/update"))
def GET_verify_email(self, token, dest):
if token and token.user_id != c.user._fullname:
# wrong user. log them out and try again.
@@ -1138,19 +1065,18 @@ def GET_verify_email(self, token, dest):
token.consume()
c.user.email_verified = True
c.user._commit()
- Award.give_if_needed("verified_email", c.user)
+ models.Award.give_if_needed("verified_email", c.user)
return self.redirect(dest)
else:
+ panes = [pages.InfoBar(message=strings.email_verify_failed),
+ pages.PrefUpdate(email=True, verify=True, password=False)
+ ]
# failure. let 'em know.
- content = PaneStack(
- [InfoBar(message=strings.email_verify_failed),
- PrefUpdate(email=True,
- verify=True,
- password=False)])
- return BoringPage(_("verify email"), content=content).render()
-
- @validate(token=VOneTimeToken(PasswordResetToken, "key"),
- key=nop("key"))
+ content = pages.PaneStack(panes)
+ return pages.BoringPage(_("verify email"), content=content).render()
+
+ @validate(token=validator.VOneTimeToken(models.PasswordResetToken, "key"),
+ key=validator.nop("key"))
def GET_resetpassword(self, token, key):
"""page hit once a user has been sent a password reset email
to verify their identity before allowing them to update their
@@ -1167,17 +1093,18 @@ def GET_resetpassword(self, token, key):
done = referer_path.startswith(request.fullpath)
elif not token:
return self.redirect("/password?expired=true")
- return BoringPage(_("reset password"),
- content=ResetPassword(key=key, done=done)).render()
+ return pages.BoringPage(_("reset password"),
+ content=pages.ResetPassword(key=key, done=done)
+ ).render()
- @validate(VUser())
+ @validate(validator.VUser())
def GET_depmod(self):
- displayPane = PaneStack()
+ displayPane = pages.PaneStack()
active_trials = {}
finished_trials = {}
- juries = Jury.by_account(c.user)
+ juries = models.Jury.by_account(c.user)
trials = trial_info([j._thing2 for j in juries])
@@ -1197,59 +1124,60 @@ def my_wrap(thing):
w.hide_score = True
w.likes = None
w.trial_mode = True
- w.render_class = LinkOnTrial
+ w.render_class = models.LinkOnTrial
w.juryvote = active_trials[thing._fullname]
return w
listing = wrap_links(fullnames, wrapper=my_wrap)
- displayPane.append(InfoBar(strings.active_trials,
- extra_class="mellow"))
+ displayPane.append(pages.InfoBar(strings.active_trials,
+ extra_class="mellow"))
displayPane.append(listing)
if finished_trials:
fullnames = sorted(finished_trials.keys(), reverse=True)
listing = wrap_links(fullnames)
- displayPane.append(InfoBar(strings.finished_trials,
- extra_class="mellow"))
+ displayPane.append(pages.InfoBar(strings.finished_trials,
+ extra_class="mellow"))
displayPane.append(listing)