Skip to content
Browse files

New features:

    * 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
  • Loading branch information...
1 parent 5ef76b9 commit 2869eaf8b9241fdb84edfab1fa0b3b264c92e2bc @ketralnis ketralnis committed
Showing with 6,169 additions and 1,952 deletions.
  1. +2 −2 r2/Makefile
  2. +1 −1 r2/babel.cfg
  3. +2 −2 r2/example.ini
  4. +5 −5 r2/ez_setup/__init__.py
  5. +5 −5 r2/r2/__init__.py
  6. +8 −7 r2/r2/commands.py
  7. +5 −5 r2/r2/config/__init__.py
  8. +5 −5 r2/r2/config/admin_routes.py
  9. +5 −5 r2/r2/config/environment.py
  10. +1 −1 r2/r2/config/middleware.py
  11. +5 −5 r2/r2/config/rewrites.py
  12. +7 −5 r2/r2/config/routing.py
  13. +5 −5 r2/r2/config/templates.py
  14. +5 −5 r2/r2/config/utils.py
  15. +5 −5 r2/r2/controllers/__init__.py
  16. +5 −5 r2/r2/controllers/admin.py
  17. +107 −36 r2/r2/controllers/api.py
  18. +5 −5 r2/r2/controllers/awards.py
  19. +19 −16 r2/r2/controllers/buttons.py
  20. +5 −5 r2/r2/controllers/captcha.py
  21. +5 −5 r2/r2/controllers/embed.py
  22. +26 −10 r2/r2/controllers/error.py
  23. +5 −5 r2/r2/controllers/errors.py
  24. +8 −9 r2/r2/controllers/feedback.py
  25. +40 −12 r2/r2/controllers/front.py
  26. +19 −8 r2/r2/controllers/i18n.py
  27. +72 −19 r2/r2/controllers/listingcontroller.py
  28. +5 −5 r2/r2/controllers/mediaembed.py
  29. +7 −5 r2/r2/controllers/post.py
  30. +5 −5 r2/r2/controllers/promotecontroller.py
  31. +6 −6 r2/r2/controllers/reddit_base.py
  32. +5 −5 r2/r2/controllers/redirect.py
  33. +5 −5 r2/r2/controllers/template.py
  34. +5 −5 r2/r2/controllers/toolbar.py
  35. +5 −5 r2/r2/controllers/validator/__init__.py
  36. +17 −5 r2/r2/controllers/validator/validator.py
  37. +5 −5 r2/r2/i18n/__init__.py
  38. +883 −452 r2/r2/i18n/r2.pot
  39. +5 −5 r2/r2/lib/__init__.py
  40. +7 −7 r2/r2/lib/amqp.py
  41. +28 −10 r2/r2/lib/app_globals.py
  42. +5 −5 r2/r2/lib/authorize/__init__.py
  43. +5 −5 r2/r2/lib/authorize/api.py
  44. +5 −5 r2/r2/lib/authorize/interaction.py
  45. +5 −5 r2/r2/lib/base.py
  46. +2 −2 r2/r2/lib/c/filters.c
  47. +1 −1 r2/r2/lib/c/recommendations/Database.cpp
  48. +1 −1 r2/r2/lib/c/recommendations/Database.h
  49. +1 −1 r2/r2/lib/c/recommendations/Dictionary.h
  50. +1 −1 r2/r2/lib/c/recommendations/ModsTable.cpp
  51. +1 −1 r2/r2/lib/c/recommendations/ModsTable.h
  52. +1 −1 r2/r2/lib/c/recommendations/Recommender.cpp
  53. +1 −1 r2/r2/lib/c/recommendations/Recommender.h
  54. +1 −1 r2/r2/lib/c/recommendations/SparseMatrix.h
  55. +1 −1 r2/r2/lib/c/recommendations/User.cpp
  56. +1 −1 r2/r2/lib/c/recommendations/User.h
  57. +1 −1 r2/r2/lib/c/recommendations/articles.cpp
  58. +1 −1 r2/r2/lib/c/recommendations/articles.h
  59. +1 −1 r2/r2/lib/c/recommendations/main.cpp
  60. +1 −1 r2/r2/lib/c/recommendations/recommend_memcache.cpp
  61. +1 −1 r2/r2/lib/c/recommendations/recommend_memcache.h
  62. +1 −1 r2/r2/lib/c/recommendations/recommender_py.h
  63. +2 −0 r2/r2/lib/c_markdown.py
  64. +121 −22 r2/r2/lib/cache.py
  65. +5 −5 r2/r2/lib/captcha.py
  66. +145 −7 r2/r2/lib/comment_tree.py
  67. +2,227 −0 r2/r2/lib/contrib/gprof2dot.py
  68. +4 −1 r2/r2/lib/contrib/markdown.py
  69. +6 −2 r2/r2/lib/contrib/memcache.py
  70. +5 −5 r2/r2/lib/contrib/nymph.py
  71. +5 −5 r2/r2/lib/count.py
  72. +10 −7 r2/r2/lib/cssfilter.py
  73. +5 −5 r2/r2/lib/db/__init__.py
  74. +5 −5 r2/r2/lib/db/alter_db.py
  75. +5 −5 r2/r2/lib/db/operators.py
  76. +78 −27 r2/r2/lib/db/queries.py
  77. +14 −2 r2/r2/lib/db/query_queue.py
  78. +5 −5 r2/r2/lib/db/sorts.py
  79. +5 −5 r2/r2/lib/db/stats.py
  80. +6 −5 r2/r2/lib/db/tdb_lite.py
  81. +27 −12 r2/r2/lib/db/tdb_sql.py
  82. +44 −11 r2/r2/lib/db/thing.py
  83. +5 −5 r2/r2/lib/db/userrel.py
  84. +5 −5 r2/r2/lib/emailer.py
  85. +76 −52 r2/r2/lib/filters.py
  86. +5 −5 r2/r2/lib/find_tz.py
  87. +78 −7 r2/r2/lib/hardcachebackend.py
  88. +5 −5 r2/r2/lib/helpers.py
  89. +5 −5 r2/r2/lib/html_source.py
  90. +5 −5 r2/r2/lib/jsonresponse.py
  91. +20 −9 r2/r2/lib/jsontemplates.py
  92. +5 −5 r2/r2/lib/lock.py
  93. +5 −5 r2/r2/lib/logger.py
  94. +5 −5 r2/r2/lib/manager/__init__.py
  95. +5 −5 r2/r2/lib/manager/db_manager.py
  96. +5 −5 r2/r2/lib/manager/tp_manager.py
  97. +5 −5 r2/r2/lib/media.py
  98. +6 −7 r2/r2/lib/memoize.py
  99. +5 −5 r2/r2/lib/menus.py
  100. +76 −5 r2/r2/lib/migrate.py
  101. +45 −28 r2/r2/lib/normalized_hot.py
  102. +12 −12 r2/r2/lib/organic.py
  103. +5 −5 r2/r2/lib/pages/__init__.py
  104. +6 −5 r2/r2/lib/pages/admin_pages.py
  105. +5 −5 r2/r2/lib/pages/graph.py
  106. +42 −18 r2/r2/lib/pages/pages.py
  107. +6 −7 r2/r2/lib/pages/things.py
  108. +6 −6 r2/r2/lib/promote.py
  109. +59 −0 r2/r2/lib/py_markdown.py
  110. +5 −5 r2/r2/lib/queues.py
  111. +5 −5 r2/r2/lib/recommendation.py
  112. +5 −5 r2/r2/lib/rising.py
  113. +5 −5 r2/r2/lib/rpc.py
  114. +5 −5 r2/r2/lib/s3cp.py
  115. +5 −5 r2/r2/lib/scraper.py
  116. +4 −4 r2/r2/lib/services.py
  117. +5 −5 r2/r2/lib/set_reddit_pops.py
  118. +31 −14 r2/r2/lib/solrsearch.py
  119. +8 −7 r2/r2/lib/strings.py
  120. +5 −5 r2/r2/lib/sup.py
  121. +7 −7 r2/r2/lib/template_helpers.py
  122. +5 −5 r2/r2/lib/test_cache.py
  123. +5 −5 r2/r2/lib/test_wrapper.py
  124. +5 −5 r2/r2/lib/tracking.py
  125. +5 −5 r2/r2/lib/traffic.py
  126. +5 −5 r2/r2/lib/translation.py
  127. +5 −5 r2/r2/lib/utils/__init__.py
  128. +5 −5 r2/r2/lib/utils/cmd_utils.py
  129. +19 −18 r2/r2/lib/utils/utils.py
  130. +5 −5 r2/r2/lib/workqueue.py
  131. +10 −10 r2/r2/lib/wrapped.py
  132. +5 −5 r2/r2/models/__init__.py
  133. +48 −27 r2/r2/models/account.py
  134. +5 −5 r2/r2/models/admintools.py
  135. +36 −22 r2/r2/models/award.py
  136. +5 −5 r2/r2/models/bidding.py
  137. +152 −36 r2/r2/models/builder.py
  138. +116 −19 r2/r2/models/link.py
  139. +9 −7 r2/r2/models/listing.py
  140. +5 −5 r2/r2/models/mail_queue.py
  141. +5 −5 r2/r2/models/populatedb.py
  142. +5 −5 r2/r2/models/printable.py
  143. +5 −5 r2/r2/models/report.py
  144. +6 −5 r2/r2/models/subreddit.py
  145. +5 −5 r2/r2/models/types.py
  146. +5 −5 r2/r2/models/update_karmas.py
  147. +9 −8 r2/r2/models/vote.py
  148. BIN r2/r2/public/static/alien-head.png
  149. +4 −0 r2/r2/public/static/css/reddit-ie7-hax.css
  150. +158 −6 r2/r2/public/static/css/reddit.css
  151. BIN r2/r2/public/static/help.png
  152. +1 −1 r2/r2/public/static/iphone/index.html
  153. +16 −7 r2/r2/public/static/js/jquery.reddit.js
  154. +61 −9 r2/r2/public/static/js/reddit.js
  155. +1 −1 r2/r2/public/static/js/sponsored.js
  156. BIN r2/r2/public/static/kill.png
  157. BIN r2/r2/public/static/mail.png
  158. BIN r2/r2/public/static/mailgray.png
  159. BIN r2/r2/public/static/red-arrow.png
  160. +5 −5 r2/r2/templates/__init__.py
  161. +5 −5 r2/r2/templates/admin/__init__.py
  162. +5 −5 r2/r2/templates/admin_rightbox.html
  163. +5 −5 r2/r2/templates/adminawardgive.html
  164. +5 −5 r2/r2/templates/adminawards.html
  165. +5 −5 r2/r2/templates/adminawardwinners.html
  166. +20 −19 r2/r2/templates/admintranslations.html
  167. +5 −5 r2/r2/templates/ads.html
  168. +5 −5 r2/r2/templates/appservicemonitor.html
  169. +1 −1 r2/r2/templates/autohandler
  170. +5 −5 r2/r2/templates/base.html
  171. +1 −1 r2/r2/templates/base.htmllite
  172. +1 −1 r2/r2/templates/base.mobile
  173. +1 −1 r2/r2/templates/base.wired
  174. +1 −1 r2/r2/templates/base.xml
  175. +5 −5 r2/r2/templates/bookmarklets.html
  176. +5 −5 r2/r2/templates/button.html
  177. +5 −5 r2/r2/templates/buttondemopanel.html
  178. +1 −1 r2/r2/templates/buttonembed.js
  179. +1 −1 r2/r2/templates/buttonlite.js
  180. +5 −5 r2/r2/templates/buttonnobody.html
  181. +7 −7 r2/r2/templates/buttontypes.html
  182. +5 −5 r2/r2/templates/captcha.html
  183. +5 −5 r2/r2/templates/clickgadget.html
  184. +5 −5 r2/r2/templates/cnameframe.html
  185. +5 −5 r2/r2/templates/comment.html
  186. +1 −1 r2/r2/templates/comment.htmllite
  187. +1 −1 r2/r2/templates/comment.mobile
  188. +1 −1 r2/r2/templates/comment.xml
  189. +6 −5 r2/r2/templates/comment_skeleton.html
  190. +5 −5 r2/r2/templates/commentspanel.html
  191. +11 −6 r2/r2/templates/createsubreddit.html
  192. +5 −5 r2/r2/templates/csserror.html
  193. +5 −5 r2/r2/templates/embed.html
  194. +5 −5 r2/r2/templates/errorpage.html
  195. +5 −5 r2/r2/templates/feedback.html
  196. +69 −0 r2/r2/templates/feedbackblurb.html
  197. +5 −5 r2/r2/templates/frame.html
  198. +6 −6 r2/r2/templates/frametoolbar.html
  199. +5 −5 r2/r2/templates/gettextheader.html
  200. +1 −1 r2/r2/templates/headerbar.mobile
  201. +1 −1 r2/r2/templates/headerbar.xml
  202. +5 −5 r2/r2/templates/helppage.html
  203. +5 −5 r2/r2/templates/infobar.html
  204. +1 −1 r2/r2/templates/infobar.htmllite
  205. +1 −1 r2/r2/templates/infobar.mobile
  206. +1 −1 r2/r2/templates/infobar.wired
  207. +1 −1 r2/r2/templates/infobar.xml
  208. +5 −5 r2/r2/templates/innertoolbarframe.html
  209. +1 −1 r2/r2/templates/jquery.reddit.js
  210. +10 −8 r2/r2/templates/link.html
  211. +1 −1 r2/r2/templates/link.htmllite
  212. +1 −1 r2/r2/templates/link.mobile
  213. +1 −1 r2/r2/templates/link.wired
  214. +1 −1 r2/r2/templates/link.xml
  215. +5 −5 r2/r2/templates/linkinfobar.html
  216. +5 −5 r2/r2/templates/linkpromoteinfobar.html
  217. +5 −5 r2/r2/templates/listing.html
  218. +1 −1 r2/r2/templates/listing.htmllite
  219. +1 −1 r2/r2/templates/listing.mobile
  220. +1 −1 r2/r2/templates/listing.wired
  221. +1 −1 r2/r2/templates/listing.xml
  222. +5 −5 r2/r2/templates/login.html
  223. +1 −1 r2/r2/templates/login.mobile
  224. +5 −5 r2/r2/templates/loginformwide.html
  225. +1 −1 r2/r2/templates/mail_opt.email
  226. +5 −5 r2/r2/templates/mediaembed.html
  227. +5 −5 r2/r2/templates/mediaembedbody.html
  228. +5 −5 r2/r2/templates/menuarea.html
  229. +1 −1 r2/r2/templates/menuarea.htmllite
  230. +1 −1 r2/r2/templates/menuarea.mobile
  231. +1 −1 r2/r2/templates/menuarea.xml
  232. +49 −28 r2/r2/templates/message.html
  233. +1 −1 r2/r2/templates/message.xml
  234. +5 −5 r2/r2/templates/messagecompose.html
  235. +5 −5 r2/r2/templates/morechildren.html
  236. +1 −1 r2/r2/templates/morechildren.htmllite
  237. +1 −1 r2/r2/templates/morechildren.mobile
  238. +1 −1 r2/r2/templates/morechildren.xml
  239. +51 −0 r2/r2/templates/moremessages.html
  240. +5 −5 r2/r2/templates/morerecursion.html
  241. +1 −1 r2/r2/templates/morerecursion.htmllite
  242. +1 −1 r2/r2/templates/morerecursion.mobile
  243. +1 −1 r2/r2/templates/morerecursion.xml
  244. +5 −5 r2/r2/templates/navbutton.html
  245. +1 −1 r2/r2/templates/navbutton.mobile
  246. +5 −5 r2/r2/templates/navmenu.html
  247. +1 −1 r2/r2/templates/navmenu.htmllite
  248. +1 −1 r2/r2/templates/navmenu.mobile
  249. +6 −5 r2/r2/templates/newlink.html
  250. +5 −5 r2/r2/templates/optout.html
  251. +5 −5 r2/r2/templates/organiclisting.html
  252. +5 −5 r2/r2/templates/over18.html
  253. +5 −5 r2/r2/templates/page_down.html
  254. +5 −5 r2/r2/templates/pagenamenav.html
  255. +1 −1 r2/r2/templates/pagenamenav.mobile
  256. +5 −5 r2/r2/templates/panestack.html
  257. +1 −1 r2/r2/templates/panestack.htmllite
  258. +1 −1 r2/r2/templates/panestack.mobile
  259. +1 −1 r2/r2/templates/panestack.wired
  260. +1 −1 r2/r2/templates/panestack.xml
  261. +5 −5 r2/r2/templates/password.html
  262. +1 −1 r2/r2/templates/passwordreset.email
  263. +5 −5 r2/r2/templates/paymentform.html
  264. +5 −5 r2/r2/templates/permalinkmessage.html
  265. +1 −1 r2/r2/templates/permalinkmessage.mobile
  266. +1 −1 r2/r2/templates/permalinkmessage.xml
  267. +5 −5 r2/r2/templates/prefdelete.html
  268. +20 −6 r2/r2/templates/prefoptions.html
  269. +5 −5 r2/r2/templates/prefupdate.html
  270. +7 −6 r2/r2/templates/printable.html
  271. +1 −1 r2/r2/templates/printable.htmllite
  272. +1 −1 r2/r2/templates/printable.mobile
  273. +16 −12 r2/r2/templates/printablebuttons.html
  274. +5 −5 r2/r2/templates/profilebar.html
  275. +5 −5 r2/r2/templates/profiling.html
  276. +2 −2 r2/r2/templates/promo_email.email
  277. +5 −5 r2/r2/templates/promote_graph.html
  278. +5 −5 r2/r2/templates/promotedlink.html
  279. +5 −5 r2/r2/templates/promotedtraffic.html
  280. +12 −6 r2/r2/templates/promotelinkform.html
  281. +5 −5 r2/r2/templates/reddit.html
  282. +1 −1 r2/r2/templates/reddit.htmllite
  283. +1 −1 r2/r2/templates/reddit.js
  284. +1 −1 r2/r2/templates/reddit.mobile
  285. +1 −1 r2/r2/templates/reddit.wired
  286. +1 −1 r2/r2/templates/reddit.xml
  287. +5 −5 r2/r2/templates/redditfooter.html
  288. +5 −5 r2/r2/templates/redditheader.html
  289. +1 −1 r2/r2/templates/redditheader.mobile
  290. +5 −5 r2/r2/templates/redditmin.html
  291. +5 −5 r2/r2/templates/reddittraffic.html
  292. +5 −5 r2/r2/templates/resetpassword.html
  293. +6 −6 r2/r2/templates/searchbar.html
  294. +1 −1 r2/r2/templates/searchbar.htmllite
  295. +1 −1 r2/r2/templates/searchbar.mobile
  296. +1 −1 r2/r2/templates/searchbar.xml
  297. +42 −0 r2/r2/templates/searchfail.html
  298. 0 r2/r2/templates/searchfail.htmllite
  299. 0 r2/r2/templates/searchfail.mobile
  300. 0 r2/r2/templates/searchfail.xml
Sorry, we could not display the entire diff because too many files (340) changed.
View
4 r2/Makefile
@@ -16,7 +16,7 @@
# 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-2009
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
@@ -94,4 +94,4 @@ md5: $(MD5S)
rtl: $(RTLCSS)
clean:
- rm $(JSTARGETS) $(CSSTARGETS) $(MD5S) $(INIS)
+ rm $(JSTARGETS) $(CSSTARGETS) $(MD5S) $(INIS)
View
2 r2/babel.cfg
@@ -16,7 +16,7 @@
## 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-2009
+## All portions of the code written by CondeNet are Copyright (c) 2006-2010
## CondeNet, Inc. All Rights Reserved.
################################################################################
View
4 r2/example.ini
@@ -117,8 +117,6 @@ allowed_css_linked_domains = my.domain.com, my.otherdomain.com
css_killswitch = False
max_sr_images = 20
-show_awards = False
-
takedown_sr = _takedowns
login_cookie = reddit_session
domain = localhost
@@ -139,6 +137,8 @@ profanity_wordlist =
solr_url =
solr_cache_time = 300
+markdown_backend = py
+
SECRET = abcdefghijklmnopqrstuvwxyz0123456789
MODSECRET = abcdefghijklmnopqrstuvwxyz0123456789
tracking_secret = abcdefghijklmnopqrstuvwxyz0123456789
View
10 r2/ez_setup/__init__.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
#!python
View
10 r2/r2/__init__.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
"""r2
View
15 r2/r2/commands.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
import paste.deploy.config
@@ -34,7 +34,7 @@
import os, sys
#
# commands that will be available by running paste with this app
-#
+#
class RunCommand(command.Command):
max_args = 2
@@ -55,6 +55,7 @@ def command(self):
here_dir = os.getcwd()
conf = appconfig(config_name, relative_to=here_dir)
+ conf.global_conf['running_as_script'] = True
conf.update(dict(app_conf=conf.local_conf,
global_conf=conf.global_conf))
paste.deploy.config.CONFIG.push_thread_config(conf)
@@ -67,7 +68,7 @@ def command(self):
# Load the wsgi app first so that everything is initialized right
wsgiapp = RegistryManager(PylonsApp())
test_app = paste.fixture.TestApp(wsgiapp)
-
+
# Query the test app to setup the environment
tresponse = test_app.get('/_test_vars')
request_id = int(tresponse.body)
View
10 r2/r2/config/__init__.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from r2.lib.cache import sgm
View
10 r2/r2/config/admin_routes.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
def add(mc):
View
10 r2/r2/config/environment.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
import os
View
2 r2/r2/config/middleware.py
@@ -16,7 +16,7 @@
# 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-2009
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
"""Pylons middleware initialization"""
View
10 r2/r2/config/rewrites.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
import re
View
12 r2/r2/config/routing.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
"""
@@ -150,6 +150,8 @@ def make_map(global_conf={}, app_conf={}):
requirements = dict(sort = 'top|controversial'))
mc('/message/compose', controller='message', action='compose')
+ mc('/message/messages/:mid', controller='message', action='listing',
+ where = "messages")
mc('/message/:where', controller='message', action='listing')
mc('/:action', controller='front',
View
10 r2/r2/config/templates.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from r2.lib.manager import tp_manager
View
10 r2/r2/config/utils.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
iters = (list, tuple, set)
View
10 r2/r2/controllers/__init__.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from listingcontroller import ListingController
View
10 r2/r2/controllers/admin.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from r2.controllers.reddit_base import RedditController
View
143 r2/r2/controllers/api.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from reddit_base import RedditController, set_user_cookie
@@ -31,7 +31,7 @@
from r2.lib.utils import get_title, sanitize_url, timeuntil, set_last_modified
from r2.lib.utils import query_string, link_from_url, timefromnow
-from r2.lib.utils import timeago
+from r2.lib.utils import timeago, tup
from r2.lib.pages import FriendList, ContributorList, ModList, \
BannedList, BoringPage, FormPage, CssError, UploadedImage, \
ClickGadget
@@ -202,7 +202,8 @@ def POST_submit(self, form, jquery, url, selftext, kind, title, save,
l._commit()
l.set_url_cache()
- queries.queue_vote(c.user, l, True, ip)
+ queries.queue_vote(c.user, l, True, ip,
+ cheater = (errors.CHEATER, None) in c.errors)
if save:
r = l._save(c.user)
queries.new_savehide(r)
@@ -258,22 +259,33 @@ def _login(self, form, user, dest='', rem = None):
@validatedForm(VRatelimit(rate_ip = True, prefix = 'login_',
error = errors.WRONG_PASSWORD),
user = VLogin(['user', 'passwd']),
+ username = VLength('user', max_length = 100),
dest = VDestination(),
rem = VBoolean('rem'),
reason = VReason('reason'))
- def POST_login(self, form, jquery, user, dest, rem, reason):
+ def POST_login(self, form, jquery, user, username, dest, rem, reason):
if reason and reason[0] == 'redirect':
dest = reason[1]
hc_key = "login_attempts-%s" % request.ip
- recent_attempts = g.hardcache.get(hc_key, 0)
+ # TODO: You-know-what (not mentioning it, just in case
+ # we accidentally release code with this comment in it)
+ # Cache lifetime for login_attmempts
+ la_expire_time = 3600 * 8
+
+ recent_attempts = g.hardcache.add(hc_key, 0, time=la_expire_time)
+
+ fake_failure = False
if recent_attempts >= 25:
- raise NotImplementedError("need proper fail msg")
- elif form.has_errors("passwd", errors.WRONG_PASSWORD):
+ g.log.error ("%s failed to login as %s (attempt #%d)"
+ % (request.ip, username, recent_attempts))
+ fake_failure = True
+
+ if fake_failure or form.has_errors("passwd", errors.WRONG_PASSWORD):
VRatelimit.ratelimit(rate_ip = True, prefix = 'login_', seconds=1)
- g.hardcache.set(hc_key, recent_attempts + 1, 3600 * 8)
+ g.hardcache.incr(hc_key, time = la_expire_time)
else:
self._login(form, user, dest, rem)
@@ -635,7 +647,8 @@ def POST_comment(self, commentform, jquery, parent, comment, ip):
else:
item, inbox_rel = Comment._new(c.user, link, parent_comment,
comment, ip)
- queries.queue_vote(c.user, item, True, ip)
+ queries.queue_vote(c.user, item, True, ip,
+ cheater = (errors.CHEATER, None) in c.errors)
#update last modified
set_last_modified(link, 'comments')
@@ -653,6 +666,7 @@ def POST_comment(self, commentform, jquery, parent, comment, ip):
# insert the new comment
jquery.insert_things(item)
+
# remove any null listings that may be present
jquery("#noresults").hide()
@@ -721,7 +735,7 @@ def POST_share(self, shareform, jquery, emails, thing, share_from, reply_to,
if should_ratelimit:
VRatelimit.ratelimit(rate_user=True, rate_ip = True,
prefix = "rate_share_")
-
+
@noresponse(VUser(),
VModhash(),
vote_type = VVotehash(('vh', 'id')),
@@ -731,13 +745,21 @@ def POST_share(self, shareform, jquery, emails, thing, share_from, reply_to,
def POST_vote(self, dir, thing, ip, vote_type):
ip = request.ip
user = c.user
+ store = True
+
if not thing or thing._deleted:
return
+ if vote_type == "rejected":
+ g.log.error("POST_vote: rejected vote (%s) from '%s' on %s (%s)"%
+ (request.params.get('dir'), c.user.name,
+ thing._fullname, request.ip))
+ store = False
+
# TODO: temporary hack until we migrate the rest of the vote data
if thing._date < datetime(2009, 4, 17, 0, 0, 0, 0, g.tz):
- g.log.debug("POST_vote: ignoring old vote on %s" % thing._fullname)
- return
+ g.log.error("POST_vote: ignoring old vote on %s" % thing._fullname)
+ store = False
# in a lock to prevent duplicate votes from people
# double-clicking the arrows
@@ -745,16 +767,18 @@ def POST_vote(self, dir, thing, ip, vote_type):
dir = (True if dir > 0
else False if dir < 0
else None)
- organic = vote_type == 'organic'
- queries.queue_vote(user, thing, dir, ip, organic)
- #update relevant caches
- if isinstance(thing, Link):
- set_last_modified(c.user, 'liked')
- set_last_modified(c.user, 'disliked')
+ organic = vote_type == 'organic'
+ queries.queue_vote(user, thing, dir, ip, organic, store = store,
+ cheater = (errors.CHEATER, None) in c.errors)
+ if store:
+ #update relevant caches
+ if isinstance(thing, Link):
+ set_last_modified(c.user, 'liked')
+ set_last_modified(c.user, 'disliked')
- # flag search indexer that something has changed
- changed(thing)
+ # flag search indexer that something has changed
+ changed(thing)
@validatedForm(VUser(),
VModhash(),
@@ -967,12 +991,13 @@ def POST_upload_sr_img(self, file, header, sponsor, name, form_id):
ip = ValidIP(),
ad_type = VOneOf('ad', ('default', 'basic', 'custom')),
ad_file = VLength('ad-location', max_length = 500),
+ sponsor_text =VLength('sponsorship-text', max_length = 500),
sponsor_name =VLength('sponsorship-name', max_length = 500),
sponsor_url = VLength('sponsorship-url', max_length = 500),
css_on_cname = VBoolean("css_on_cname"),
)
def POST_site_admin(self, form, jquery, name, ip, sr, ad_type, ad_file,
- sponsor_url, sponsor_name, **kw):
+ sponsor_text, sponsor_url, sponsor_name, **kw):
# the status button is outside the form -- have to reset by hand
form.parent().set_html('.status', "")
@@ -1004,6 +1029,7 @@ def POST_site_admin(self, form, jquery, name, ip, sr, ad_type, ad_file,
elif (form.has_errors(None, errors.INVALID_OPTION) or
form.has_errors('description', errors.TOO_LONG)):
pass
+
#creating a new reddit
elif not sr:
#sending kw is ok because it was sanitized above
@@ -1032,6 +1058,7 @@ def POST_site_admin(self, form, jquery, name, ip, sr, ad_type, ad_file,
if ad_type != "custom":
ad_file = Subreddit._defaults['ad_file']
sr.ad_file = ad_file
+ sr.sponsorship_text = sponsor_text or ""
sr.sponsorship_url = sponsor_url or None
sr.sponsorship_name = sponsor_name or None
@@ -1053,7 +1080,10 @@ def POST_site_admin(self, form, jquery, name, ip, sr, ad_type, ad_file,
changed(sr)
form.parent().set_html('.status', _("saved"))
- if redir:
+ # don't go any further until the form validates
+ if form.has_error():
+ return
+ elif redir:
form.redirect(redir)
else:
jquery.refresh()
@@ -1109,14 +1139,39 @@ def POST_unsave(self, thing):
@noresponse(VUser(),
VModhash(),
+ thing = VByName('id', multiple = True))
+ def POST_collapse_message(self, thing):
+ if not thing:
+ return
+ for t in tup(thing):
+ if hasattr(t, "to_id") and c.user._id == t.to_id:
+ t.to_collapse = True
+ elif hasattr(t, "author_id") and c.user._id == t.author_id:
+ t.author_collapse = True
+ t._commit()
+
+ @noresponse(VUser(),
+ VModhash(),
+ thing = VByName('id', multiple = True))
+ def POST_uncollapse_message(self, thing):
+ if not thing:
+ return
+ for t in tup(thing):
+ if hasattr(t, "to_id") and c.user._id == t.to_id:
+ t.to_collapse = False
+ elif hasattr(t, "author_id") and c.user._id == t.author_id:
+ t.author_collapse = False
+ t._commit()
+
+ @noresponse(VUser(),
+ VModhash(),
thing = VByName('id'))
def POST_unread_message(self, thing):
if not thing:
return
if hasattr(thing, "to_id") and c.user._id != thing.to_id:
return
- thing.new = True
- thing._commit()
+ queries.set_unread(thing, True)
@noresponse(VUser(),
VModhash(),
@@ -1125,10 +1180,7 @@ def POST_read_message(self, thing):
if not thing: return
if hasattr(thing, "to_id") and c.user._id != thing.to_id:
return
- thing.new = False
- thing._commit()
-
-
+ queries.set_unread(thing, False)
@noresponse(VUser(),
VModhash(),
@@ -1148,6 +1200,24 @@ def POST_unhide(self, thing):
queries.new_savehide(r)
+ @validatedForm(VUser(),
+ parent = VByName('parent_id'))
+ def POST_moremessages(self, form, jquery, parent):
+ if not parent.can_view():
+ return self.abort(403,'forbidden')
+
+ builder = MessageBuilder(c.user, parent = parent, skip = False)
+ listing = Listing(builder).listing()
+ a = []
+ for item in listing.things:
+ a.append(item)
+ for x in item.child.things:
+ a.append(x)
+ for item in a:
+ if hasattr(item, "child"):
+ item.child = None
+ jquery.things(parent._fullname).parent().replace_things(a, False, True)
+
@validatedForm(link = VByName('link_id'),
sort = VMenu('where', CommentSortMenu),
children = VCommentIDs('children'),
@@ -1221,7 +1291,8 @@ def GET_bookmarklet(self, action, uh, links):
#vote up all of the links
for link in links:
queries.queue_vote(c.user, link,
- action == 'like', request.ip)
+ action == 'like', request.ip,
+ cheater = (errors.CHEATER, None) in c.errors)
elif action == 'save':
link = max(links, key = lambda x: x._score)
r = link._save(c.user)
@@ -1285,7 +1356,7 @@ def POST_new_captcha(self, form, jquery, *a, **kw):
jquery("body").captcha(get_iden())
@noresponse(VAdmin(),
- tr = VTranslation("id"),
+ tr = VTranslation("lang"),
user = nop('user'))
def POST_deltranslator(self, tr, user):
if tr:
@@ -1398,8 +1469,8 @@ def POST_givetrophy(self, form, jquery, award, description,
else:
cup_expiration = None
- t = Trophy._new(recipient, award, description=description,
- url=url, cup_expiration=cup_expiration)
+ t = Trophy._new(recipient, award, description=description, url=url,
+ cup_info=dict(expiration=cup_expiration))
form.set_html(".status", _('saved'))
View
10 r2/r2/controllers/awards.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from pylons import request, g
View
35 r2/r2/controllers/buttons.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from reddit_base import RedditController
@@ -41,6 +41,7 @@ def buttontype(self):
def get_wrapped_link(self, url, link = None, wrapper = None):
try:
+ links = []
if link:
links = [link]
else:
@@ -48,7 +49,7 @@ def get_wrapped_link(self, url, link = None, wrapper = None):
try:
links = tup(Link._by_url(url, sr))
except NotFound:
- links = []
+ pass
if links:
kw = {}
@@ -80,10 +81,9 @@ def get_wrapped_link(self, url, link = None, wrapper = None):
vote = VBoolean('vote', default=True),
newwindow = VBoolean('newwindow'),
width = VInt('width', 0, 800),
- link = VByName('id'))
- def GET_button_content(self, url, title, css, vote, newwindow, width, link):
-
-
+ l = VByName('id'))
+ def GET_button_content(self, url, title, css, vote, newwindow, width, l):
+
# no buttons on domain listings
if isinstance(c.site, DomainSR):
c.site = Default
@@ -94,17 +94,20 @@ def GET_button_content(self, url, title, css, vote, newwindow, width, link):
css != 'http://www.wired.com/css/redditsocial.css'):
css = None
- if link:
- url = link.url
- title = link.title
+ if l:
+ url = l.url
+ title = l.title
+ kw = {}
+ if title:
+ kw = dict(title = title)
wrapper = make_wrapper(Button if vote else ButtonNoBody,
url = url,
target = "_new" if newwindow else "_parent",
- title = title, vote = vote, bgcolor = c.bgcolor,
+ vote = vote, bgcolor = c.bgcolor,
width = width, css = css,
- button = self.buttontype())
+ button = self.buttontype(), **kw)
- l = self.get_wrapped_link(url, link, wrapper)
+ l = self.get_wrapped_link(url, l, wrapper)
res = l.render()
c.response.content = spaceCompress(res)
return c.response
View
10 r2/r2/controllers/captcha.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from reddit_base import RedditController
View
10 r2/r2/controllers/embed.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from reddit_base import RedditController, proxyurl
View
36 r2/r2/controllers/error.py
@@ -6,20 +6,21 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
import os.path
+from mako.filters import url_escape
import paste.fileapp
from pylons.middleware import error_document_template, media_path
@@ -117,7 +118,12 @@ def send404(self):
if 'usable_error_content' in request.environ:
return request.environ['usable_error_content']
if c.site._spam and not c.user_is_admin:
- message = (strings.banned_subreddit % dict(link = '/feedback'))
+ subject = ("the subreddit /r/%s has been incorrectly banned" %
+ c.site.name)
+ message = (strings.banned_subreddit %
+ dict(link = '/message/compose?to=%s&subject=%s' %
+ (g.admin_message_acct,
+ url_escape(subject))))
res = pages.RedditError(_('this reddit has been banned'),
unsafe(safemarkdown(message)))
@@ -125,6 +131,19 @@ def send404(self):
else:
return pages.Reddit404().render()
+ def send503(self):
+ c.response.status_code = 503
+ if 'retry_after' in request.environ:
+ c.response.headers['Retry-After'] = request.environ['retry_after']
+ else:
+ c.response.headers['Retry-After'] = 1
+
+ if 'usable_error_content' in request.environ:
+ return request.environ['usable_error_content']
+ else:
+ c.response.content = toofast
+ return c.response
+
def GET_document(self):
try:
#no cookies on errors
@@ -145,10 +164,7 @@ def GET_document(self):
elif code == '500':
return redditbroke % rand_strings.sadmessages
elif code == '503':
- c.response.status_code = 503
- c.response.headers['Retry-After'] = 1
- c.response.content = toofast
- return c.response
+ return self.send503()
elif code == '304':
if request.GET.has_key('x-sup-id'):
c.response.headers['x-sup-id'] = request.GET.get('x-sup-id')
View
10 r2/r2/controllers/errors.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from r2.lib.utils import Storage, tup
View
17 r2/r2/controllers/feedback.py
@@ -6,23 +6,23 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from reddit_base import RedditController
from pylons import c, request
from pylons.i18n import _
-from r2.lib.pages import FormPage, Feedback, Captcha, PaneStack, SelfServeBlurb
+from r2.lib.pages import FormPage, Feedback, Captcha, PaneStack, SelfServeBlurb, FeedbackBlurb
class FeedbackController(RedditController):
@@ -32,13 +32,12 @@ def GET_ad_inq(self):
loginbox = False).render()
def GET_feedback(self):
- title = _("send reddit feedback")
return FormPage('feedback',
- content = Feedback(title=title, action='feedback'),
+ content = FeedbackBlurb(),
loginbox = False).render()
def GET_i18n(self):
title = _("help translate reddit into your language")
- return FormPage('help translate',
+ return FormPage(_('help translate'),
content = Feedback(title=title, action='i18n'),
loginbox = False).render()
View
52 r2/r2/controllers/front.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from validator import *
@@ -31,16 +31,18 @@
from r2.lib.utils import to36, sanitize_url, check_cheating, title_to_url
from r2.lib.utils import query_string, UrlParser, link_from_url, link_duplicates
from r2.lib.template_helpers import get_domain
+from r2.lib.filters import unsafe
from r2.lib.emailer import has_opted_out, Email
from r2.lib.db.operators import desc
from r2.lib.db import queries
from r2.lib.strings import strings
from r2.lib.solrsearch import RelatedSearchQuery, SubredditSearchQuery, LinkSearchQuery
+from r2.lib.contrib.pysolr import SolrError
from r2.lib import jsontemplates
from r2.lib import sup
import r2.lib.db.thing as thing
from listingcontroller import ListingController
-from pylons import c, request
+from pylons import c, request, request, Response
import random as rand
import re
@@ -228,7 +230,7 @@ def GET_comments(self, article, comment, context, sort, num_comments):
comment, context)
listing = NestedListing(builder, num = num,
parent_name = article._fullname)
-
+
displayPane = PaneStack()
# if permalink page, add that message first to the content
@@ -238,11 +240,12 @@ def GET_comments(self, article, comment, context, sort, num_comments):
# insert reply box only for logged in user
if c.user_is_loggedin and can_comment_link(article) and not is_api():
#no comment box for permalinks
+ display = not bool(comment)
displayPane.append(UserText(item = article, creating = True,
post_form = 'comment',
- display = not bool(comment),
+ display = display,
cloneable = True))
-
+
# finally add the comment listing
displayPane.append(listing.listing())
@@ -469,12 +472,13 @@ def GET_search(self, query, num, time, reverse, after, count, langs, sort):
SearchSortMenu(default=sort)],
search_params = dict(sort = sort, t = time),
infotext = infotext).render()
-
+
return res
-
+
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,
@@ -484,7 +488,31 @@ def _search(self, query_obj, num, after, reverse, count=0):
# have to do it in two steps since total_num and timing are only
# computed after fetch_more
- res = listing.listing()
+ try:
+ res = listing.listing()
+ except SolrError, e:
+ errmsg = "SolrError: %r %r" % (e, query_obj)
+
+ if (str(e) == 'None'):
+ # Production error logs only get non-None errors
+ g.log.debug(errmsg)
+ else:
+ g.log.error(errmsg)
+
+ sf = SearchFail()
+ sb = SearchBar(prev_search = query_obj.q)
+
+ us = unsafe(sb.render() + sf.render())
+
+ errpage = pages.RedditError(_('search failed'), us)
+
+ c.response = Response()
+ c.response.status_code = 503
+ request.environ['usable_error_content'] = errpage.render()
+ request.environ['retry_after'] = 60
+
+ abort(503)
+
timing = time_module.time() - builder.start_time
return builder.total_num, timing, res
View
27 r2/r2/controllers/i18n.py
@@ -6,22 +6,23 @@
# 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-2009
+#
+# 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
+from r2.lib.pages import UnfoundPage, AdminTranslations, \
+ AdminPage, Translator_Message
from r2.lib.translation import Translator, TranslatorTemplate, get_translator
from validator import *
@@ -49,10 +50,18 @@ class I18nController(RedditController):
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")
@@ -60,7 +69,8 @@ def POST_adduser(self, lang, a):
VAdmin())
def GET_list(self):
res = AdminPage(content = AdminTranslations(),
- title = 'translate reddit').render()
+ title = 'translate reddit',
+ show_sidebar = False).render()
return res
@@ -85,7 +95,8 @@ def GET_edit(self, lang):
else:
content = UnfoundPage()
res = AdminPage(content = content,
- title = 'translate reddit').render()
+ title = 'translate reddit',
+ show_sidebar = False).render()
return res
@validate(VTranslationEnabled(),
View
91 r2/r2/controllers/listingcontroller.py
@@ -6,17 +6,17 @@
# 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-2009
+#
+# All portions of the code written by CondeNet are Copyright (c) 2006-2010
# CondeNet, Inc. All Rights Reserved.
################################################################################
from reddit_base import RedditController, base_listing
@@ -39,10 +39,12 @@
from r2.lib.utils import iters, check_cheating, timeago
from r2.lib import sup
from r2.lib.promote import PromoteSR
+from r2.lib.contrib.pysolr import SolrError
from admin import admin_profile_query
from pylons.i18n import _
+from pylons import Response
import random
@@ -147,7 +149,29 @@ def listing(self):
if c.site.path == PromoteSR.path and not c.user_is_sponsor:
abort(403, 'forbidden')
listing = LinkListing(self.builder_obj, show_nums = self.show_nums)
- return listing.listing()
+ try:
+ return listing.listing()
+ except SolrError, e:
+ errmsg = "SolrError: %r %r" % (e, self.builder_obj)
+
+ if (str(e) == 'None'):
+ # Production error logs only get non-None errors
+ g.log.debug(errmsg)
+ else:
+ g.log.error(errmsg)
+
+ sf = SearchFail()
+
+ us = unsafe(sf.render())
+
+ errpage = pages.RedditError(_('search failed'), us)
+
+ c.response = Response()
+ c.response.status_code = 503
+ request.environ['usable_error_content'] = errpage.render()
+ request.environ['retry_after'] = 60
+
+ abort(503)
def title(self):
"""Page <title>"""
@@ -229,7 +253,7 @@ def query(self):
and not isinstance(c.site, FakeSubreddit)
and self.after is None
and self.count == 0):
- return [l._fullname for l in get_hot(c.site)]
+ return get_hot(c.site, only_fullnames = True)
else:
return c.site.get_links('hot', 'all')
@@ -483,8 +507,10 @@ class MessageController(ListingController):
@property
def menus(self):
- if self.where in ('inbox', 'messages', 'comments', 'selfreply'):
+ if self.where in ('inbox', 'messages', 'comments',
+ 'selfreply', 'unread'):
buttons = (NavButton(_("all"), "inbox"),
+ NavButton(_("unread"), "unread"),
NavButton(plurals.messages, "messages"),
NavButton(_("comment replies"), 'comments'),
NavButton(_("post replies"), 'selfreply'))
@@ -509,14 +535,36 @@ def builder_wrapper(thing):
w.permalink, w._fullname = p, f
else:
w = ListingController.builder_wrapper(thing)
-
- if c.user.pref_mark_messages_read and thing.new:
- w.new = True
- thing.new = False
- thing._commit()
return w
+ def builder(self):
+ if self.where == 'messages':
+ if self.message:
+ if self.message.first_message:
+ parent = Message._byID(self.message.first_message)
+ else:
+ parent = self.message
+ return MessageBuilder(c.user, parent = parent,
+ skip = False,
+ focal = self.message,
+ wrap = self.builder_wrapper,
+ num = self.num)
+ elif c.user.pref_threaded_messages:
+ skip = (c.render_style == "html")
+ return MessageBuilder(c.user, wrap = self.builder_wrapper,
+ skip = skip,
+ num = self.num,
+ after = self.after,
+ reverse = self.reverse)
+ return ListingController.builder(self)
+
+ def listing(self):
+ if (self.where == 'messages' and
+ (c.user.pref_threaded_messages or self.message)):
+ return Listing(self.builder_obj).listing()
+ return ListingController.listing(self)
+
def query(self):
if self.where == 'messages':
q = queries.get_inbox_messages(c.user)
@@ -524,24 +572,28 @@ def query(self):
q = queries.get_inbox_comments(c.user)
elif self.where == 'selfreply':
q = queries.get_inbox_selfreply(c.user)
- if self.where == 'inbox':
+ elif self.where == 'inbox':
q = queries.get_inbox(c.user)
+ elif self.where == 'unread':
+ q = queries.get_unread_inbox(c.user)
+ elif self.where == 'sent':
+ q = queries.get_sent(c.user)
+ if self.where != 'sent':
#reset the inbox
if c.have_messages and self.mark != 'false':
c.user.msgtime = False
c.user._commit()
- elif self.where == 'sent':
- q = queries.get_sent(c.user)
-
return q
@validate(VUser(),
+ message = VMessageID('mid'),
mark = VOneOf('mark',('true','false'), default = 'true'))
- def GET_listing(self, where, mark, **env):